@datagrok/proteomics 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -3
- package/CLAUDE.md +178 -0
- package/README.md +195 -3
- package/detectors.js +152 -9
- package/dist/package-test.js +1 -1744
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -146
- package/dist/package.js.map +1 -1
- package/docs/personas-and-capabilities.md +165 -0
- package/files/demo/README.md +264 -0
- package/files/demo/cptac-spike-in.txt +1571 -0
- package/files/demo/enrichment-demo.csv +120 -0
- package/files/demo/fragpipe-smoke-test.tsv +11 -0
- package/files/demo/proteinGroups.txt +28 -0
- package/files/demo/spectronaut-hye-candidates.tsv +94 -0
- package/files/demo/spectronaut-hye-demo.tsv +8761 -0
- package/files/demo/spectronaut-hye-mix.tsv +8761 -0
- package/files/demo/spectronaut-hye-precursor-golden.json +938 -0
- package/files/demo/spectronaut-hye-precursor-golden.tsv +235 -0
- package/files/demo/spectronaut-hye-precursor.tsv +493 -0
- package/images/enrichment-crosslink.png +0 -0
- package/images/enrichment-term-selected.png +0 -0
- package/images/hero.png +0 -0
- package/images/pipeline.svg +80 -0
- package/package.json +87 -62
- package/scripts/deqms_de.R +60 -0
- package/scripts/limma_de.R +42 -0
- package/scripts/vsn_normalize.R +19 -0
- package/src/analysis/differential-expression.ts +450 -0
- package/src/analysis/enrichment-export.ts +101 -0
- package/src/analysis/enrichment.ts +602 -0
- package/src/analysis/experiment-setup.ts +199 -0
- package/src/analysis/imputation.ts +407 -0
- package/src/analysis/log2-scale.ts +139 -0
- package/src/analysis/normalization.ts +255 -0
- package/src/analysis/pca.ts +254 -0
- package/src/analysis/spc-storage.ts +515 -0
- package/src/analysis/spc.ts +544 -0
- package/src/analysis/subcellular-location.ts +431 -0
- package/src/demo/enrichment-demo.ts +94 -0
- package/src/demo/proteomics-demo.ts +123 -0
- package/src/global.d.ts +15 -0
- package/src/menu.ts +133 -0
- package/src/package-api.ts +136 -14
- package/src/package-test.ts +45 -20
- package/src/package.g.ts +161 -0
- package/src/package.ts +1029 -17
- package/src/panels/protein-focus.ts +63 -0
- package/src/panels/published-analysis-panel.ts +151 -0
- package/src/panels/uniprot-panel.ts +349 -0
- package/src/parsers/fragpipe-parser.ts +200 -0
- package/src/parsers/generic-parser.ts +197 -0
- package/src/parsers/maxquant-parser.ts +162 -0
- package/src/parsers/shared-utils.ts +163 -0
- package/src/parsers/spectronaut-candidates-parser.ts +307 -0
- package/src/parsers/spectronaut-parser.ts +604 -0
- package/src/publishing/assert-published-shape.ts +260 -0
- package/src/publishing/post-open-recovery.ts +104 -0
- package/src/publishing/publish-project.ts +515 -0
- package/src/publishing/publish-settings.ts +59 -0
- package/src/publishing/publish-state.ts +316 -0
- package/src/publishing/share-dialog.ts +171 -0
- package/src/publishing/trim-dataframe.ts +247 -0
- package/src/tests/analysis.ts +658 -0
- package/src/tests/enrichment-export.ts +61 -0
- package/src/tests/enrichment-visualization.ts +340 -0
- package/src/tests/enrichment.ts +224 -0
- package/src/tests/fragpipe-e2e.ts +74 -0
- package/src/tests/fragpipe-parser.ts +147 -0
- package/src/tests/gene-label-resolver.ts +387 -0
- package/src/tests/generic-parser.ts +152 -0
- package/src/tests/group-mean-correlation.ts +139 -0
- package/src/tests/log2-scale.ts +93 -0
- package/src/tests/organisms.ts +56 -0
- package/src/tests/parsers.ts +182 -0
- package/src/tests/publish-roundtrip.ts +584 -0
- package/src/tests/publish-spike.ts +377 -0
- package/src/tests/qc-dashboard.ts +210 -0
- package/src/tests/smart-pathway-filter.ts +193 -0
- package/src/tests/spc-formula-lines-spike.ts +129 -0
- package/src/tests/spc.ts +640 -0
- package/src/tests/spectronaut-candidates-e2e.ts +140 -0
- package/src/tests/spectronaut-candidates-parser.ts +398 -0
- package/src/tests/spectronaut-parser.ts +668 -0
- package/src/tests/subcellular-location.ts +361 -0
- package/src/tests/uniprot-panel.ts +202 -0
- package/src/tests/volcano.ts +603 -0
- package/src/utils/column-detection.ts +28 -0
- package/src/utils/gene-label-resolver.ts +443 -0
- package/src/utils/organisms.ts +82 -0
- package/src/utils/proteomics-types.ts +30 -0
- package/src/viewers/enrichment-viewers.ts +274 -0
- package/src/viewers/group-mean-correlation.ts +218 -0
- package/src/viewers/heatmap.ts +168 -0
- package/src/viewers/pca-plot.ts +169 -0
- package/src/viewers/qc-computations.ts +266 -0
- package/src/viewers/qc-dashboard.ts +176 -0
- package/src/viewers/spc-dashboard.ts +755 -0
- package/src/viewers/volcano.ts +690 -0
- package/test-console-output-1.log +2055 -0
- package/test-record-1.mp4 +0 -0
- package/tools/derive-precursor-golden-sidecar.mjs +81 -0
- package/tools/generate-enrichment-fixture.sh +160 -0
- package/tools/generate-spectronaut-candidates-fixture.mjs +212 -0
- package/tools/generate-spectronaut-precursor-fixture.mjs +128 -0
- package/tools/spectronaut-aggregate.sh +46 -0
- package/tools/spectronaut-aggregate.sql +80 -0
- package/tsconfig.json +18 -71
- package/webpack.config.js +86 -45
- package/.eslintignore +0 -1
- package/.eslintrc.json +0 -56
- package/LICENSE +0 -674
- package/package.png +0 -0
- package/scripts/number_antibody.py +0 -190
- package/scripts/number_antibody_abnumber.py +0 -177
- package/scripts/number_antibody_anarci.py +0 -200
package/dist/package.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;ACAA,oB;;;;;;;;;;ACAA,sB;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;UACA;;;;;WC5BA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA,E;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA,E;;;;;WCPA,wF;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D,E;;;;;;;;;;;;;;;;;;;;;ACNA,4BAA4B;AAC5B,yFAAyF;AAC/C;AAEJ;AACV;AAErB,MAAM,QAAQ,GAAG,IAAI,oDAAU,EAAE,CAAC;AAEzC,YAAY;AACL,SAAS,IAAI;IAClB,oDAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAEM,MAAM,gBAAgB;CAE5B","sources":["webpack://proteomics/./src/package.g.ts","webpack://proteomics/external var \"DG\"","webpack://proteomics/external var \"grok\"","webpack://proteomics/webpack/bootstrap","webpack://proteomics/webpack/runtime/compat get default export","webpack://proteomics/webpack/runtime/define property getters","webpack://proteomics/webpack/runtime/hasOwnProperty shorthand","webpack://proteomics/webpack/runtime/make namespace object","webpack://proteomics/./src/package.ts"],"sourcesContent":["import * as DG from 'datagrok-api/dg';\n","module.exports = DG;","module.exports = grok;","// 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\tif (!(moduleId in __webpack_modules__)) {\n\t\tdelete __webpack_module_cache__[moduleId];\n\t\tvar e = new Error(\"Cannot find module '\" + moduleId + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\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 = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (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 = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (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};","/* eslint-disable max-len */\r\n/* Do not change these import lines to match external modules in webpack configuration */\r\nimport * as grok from 'datagrok-api/grok';\r\nimport * as ui from 'datagrok-api/ui';\r\nimport * as DG from 'datagrok-api/dg';\r\nexport * from './package.g';\r\n\r\nexport const _package = new DG.Package();\r\n\r\n//name: info\r\nexport function info() {\r\n grok.shell.info(_package.webRoot);\r\n}\r\n\r\nexport class PackageFunctions {\r\n \r\n}\r\n"],"names":[],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"package.js","mappings":"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","sources":["webpack://proteomics/./node_modules/@datagrok-libraries/test/src/dataframe-utils.js","webpack://proteomics/./node_modules/@datagrok-libraries/test/src/test.js","webpack://proteomics/./node_modules/dayjs/dayjs.min.js","webpack://proteomics/./node_modules/fast-sha256/sha256.js","webpack://proteomics/./node_modules/jstat/dist/jstat.js","webpack://proteomics/./node_modules/@datagrok-libraries/utils/src/array-utils.js","webpack://proteomics/./node_modules/@datagrok-libraries/statistics/src/tests.js","webpack://proteomics/./node_modules/@datagrok-libraries/statistics/src/multiple-tests.js","webpack://proteomics/./src/analysis/differential-expression.ts","webpack://proteomics/./src/analysis/enrichment-export.ts","webpack://proteomics/./src/analysis/enrichment.ts","webpack://proteomics/./src/analysis/experiment-setup.ts","webpack://proteomics/./src/analysis/imputation.ts","webpack://proteomics/./src/analysis/log2-scale.ts","webpack://proteomics/./src/analysis/normalization.ts","webpack://proteomics/./src/analysis/spc-storage.ts","webpack://proteomics/./src/analysis/spc.ts","webpack://proteomics/./src/analysis/subcellular-location.ts","webpack://proteomics/./src/panels/protein-focus.ts","webpack://proteomics/./src/parsers/generic-parser.ts","webpack://proteomics/./src/viewers/heatmap.ts","webpack://proteomics/./src/viewers/pca-plot.ts","webpack://proteomics/./src/analysis/pca.ts","webpack://proteomics/./src/viewers/qc-dashboard.ts","webpack://proteomics/./src/panels/published-analysis-panel.ts","webpack://proteomics/./src/menu.ts","webpack://proteomics/./src/package.g.ts","webpack://proteomics/./src/package.ts","webpack://proteomics/./src/demo/proteomics-demo.ts","webpack://proteomics/./src/demo/enrichment-demo.ts","webpack://proteomics/./src/publishing/share-dialog.ts","webpack://proteomics/./src/panels/uniprot-panel.ts","webpack://proteomics/./src/parsers/fragpipe-parser.ts","webpack://proteomics/./src/parsers/maxquant-parser.ts","webpack://proteomics/./src/parsers/shared-utils.ts","webpack://proteomics/./src/parsers/spectronaut-candidates-parser.ts","webpack://proteomics/./src/parsers/spectronaut-parser.ts","webpack://proteomics/./src/publishing/assert-published-shape.ts","webpack://proteomics/./src/publishing/post-open-recovery.ts","webpack://proteomics/./src/publishing/trim-dataframe.ts","webpack://proteomics/./src/publishing/publish-project.ts","webpack://proteomics/./src/publishing/publish-settings.ts","webpack://proteomics/./src/publishing/publish-state.ts","webpack://proteomics/./src/utils/column-detection.ts","webpack://proteomics/./src/utils/gene-label-resolver.ts","webpack://proteomics/./src/utils/organisms.ts","webpack://proteomics/./src/utils/proteomics-types.ts","webpack://proteomics/./src/viewers/enrichment-viewers.ts","webpack://proteomics/./src/viewers/group-mean-correlation.ts","webpack://proteomics/./src/viewers/qc-computations.ts","webpack://proteomics/./src/viewers/spc-dashboard.ts","webpack://proteomics/./src/viewers/volcano.ts","webpack://proteomics/external var \"DG\"","webpack://proteomics/external var \"grok\"","webpack://proteomics/external var \"rxjs\"","webpack://proteomics/external var \"rxjs.operators\"","webpack://proteomics/external var \"ui\"","webpack://proteomics/webpack/bootstrap","webpack://proteomics/webpack/runtime/compat get default export","webpack://proteomics/webpack/runtime/define property getters","webpack://proteomics/webpack/runtime/hasOwnProperty shorthand","webpack://proteomics/webpack/runtime/make namespace object","webpack://proteomics/webpack/startup"],"sourcesContent":["import * as sha256 from 'fast-sha256';\n/**\n * For columns of string type. Checks whether column contains empty values and removes corresponding rows in case user selects to remove.\n *\n */\nexport function removeEmptyStringRows(table, col) {\n const cats = col.categories;\n const emptyRawInd = cats.map((val, ind) => !val ? ind : null).filter((it) => it !== null);\n const rawData = [...col.getRawData()];\n const emptyRawsIndexes = [];\n let removedRowsCounter = 0;\n for (let i = 0; i < table.rowCount; i++) {\n if (emptyRawInd.includes(rawData[i])) {\n table.rows.removeAt(i - removedRowsCounter);\n emptyRawsIndexes.push(i);\n removedRowsCounter += 1;\n }\n }\n return emptyRawsIndexes;\n}\nexport function hashDataFrame(table, names) {\n names !== null && names !== void 0 ? names : (names = table.columns.names());\n const hasher = new sha256.Hash();\n const order = table.getSortedOrder(names);\n const encoder = new TextEncoder();\n for (const name of names) {\n const column = table.columns.byName(name);\n const dataArray = column.getRawData();\n const isString = column.type == DG.TYPE.STRING;\n const cats = column.categories;\n for (let i = 0; i < dataArray.length; i++) {\n if (isString) {\n const data = cats[dataArray[order[i]]];\n hasher.update(encoder.encode(data));\n }\n else {\n const data = dataArray[order[i]];\n hasher.update(Uint8Array.from([data]));\n }\n }\n }\n return hasher.digest();\n}\nexport const testData = DG.DataFrame.fromCsv(`countries,fasta,smiles,molregno,LON,Zip Code,Street Address Line 1,ImageUrl,user_id,error_message,xray,flag,magnitude,CS-id,pdb_id,accel_a,time_offset,chart,fit,Questions,empty_number,empty_string\nBelgium,MSNFHNEHVMQFYRNNLKTKGVFGRQ,CC(C(=O)OCCCc1cccnc1)c2cccc(c2)C(=O)c3ccccc3,1480014,36.276729583740234,995042300,14016 ROUTE 31W,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,1,1,1QBS,1,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[2.497360340644872, 1.7058694986686864, 5.278052678195135, 0.16000320889028383],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":2.374499797821045},{\"\"x\"\":0.6000000238418579,\"\"y\"\":2.6242473125457764},{\"\"x\"\":1.100000023841858,\"\"y\"\":2.367267608642578},{\"\"x\"\":1.600000023841858,\"\"y\"\":2.6723148822784424},{\"\"x\"\":2.0999999046325684,\"\"y\"\":2.6537344455718994},{\"\"x\"\":2.5999999046325684,\"\"y\"\":2.3651671409606934},{\"\"x\"\":3.0999999046325684,\"\"y\"\":2.5654284954071045},{\"\"x\"\":3.5999999046325684,\"\"y\"\":2.4160959720611572},{\"\"x\"\":4.099999904632568,\"\"y\"\":2.286726713180542},{\"\"x\"\":4.599999904632568,\"\"y\"\":2.5100042819976807},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.6676985025405884},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.680136501789093},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.3391543924808502},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.09038983285427094},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.19802775979042053}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[7.525235855508179, 1.3186911876809984, 5.335672608564294, 0.7860743343958098],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":7.988070487976074},{\"\"x\"\":0.6000000238418579,\"\"y\"\":7.018453121185303},{\"\"x\"\":1.100000023841858,\"\"y\"\":8.115279197692871},{\"\"x\"\":1.600000023841858,\"\"y\"\":7.486658096313477},{\"\"x\"\":2.0999999046325684,\"\"y\"\":7.396438121795654},{\"\"x\"\":2.5999999046325684,\"\"y\"\":7.477052211761475},{\"\"x\"\":3.0999999046325684,\"\"y\"\":6.913095474243164},{\"\"x\"\":3.5999999046325684,\"\"y\"\":8.01385498046875},{\"\"x\"\":4.099999904632568,\"\"y\"\":6.985900402069092},{\"\"x\"\":4.599999904632568,\"\"y\"\":6.970335960388184},{\"\"x\"\":5.099999904632568,\"\"y\"\":5.448817253112793},{\"\"x\"\":5.599999904632568,\"\"y\"\":2.5534818172454834},{\"\"x\"\":6.099999904632568,\"\"y\"\":1.893947958946228},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.6340042352676392},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.8403874039649963}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,100,abc\nBurundi,MDYKETLLMPKTDFPMRGGLPNKEPQIQEKW,COc1ccc2cc(ccc2c1)C(C)C(=O)Oc3ccc(C)cc3OC,1480015,36.276729583740234,995073444,80 STATE HIGHWAY 310,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,2,2,1ZP8,2,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[4.431460753103398, 2.1691498799246745, 5.266445597102774, 0.7825762827017926],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":4.751083850860596},{\"\"x\"\":0.6000000238418579,\"\"y\"\":4.203000068664551},{\"\"x\"\":1.100000023841858,\"\"y\"\":4.415858745574951},{\"\"x\"\":1.600000023841858,\"\"y\"\":4.68414306640625},{\"\"x\"\":2.0999999046325684,\"\"y\"\":4.198400974273682},{\"\"x\"\":2.5999999046325684,\"\"y\"\":4.179222106933594},{\"\"x\"\":3.0999999046325684,\"\"y\"\":4.638473987579346},{\"\"x\"\":3.5999999046325684,\"\"y\"\":4.708553314208984},{\"\"x\"\":4.099999904632568,\"\"y\"\":4.291589260101318},{\"\"x\"\":4.599999904632568,\"\"y\"\":4.038082599639893},{\"\"x\"\":5.099999904632568,\"\"y\"\":3.4349939823150635},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.2194708585739136},{\"\"x\"\":6.099999904632568,\"\"y\"\":1.1920831203460693},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.5352635979652405},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.3346920311450958}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[2.339458017970126, -1.0734184310171178, 4.746332950550934, 0.2482416857595658],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":0.2139337658882141},{\"\"x\"\":0.6000000238418579,\"\"y\"\":0.4269562065601349},{\"\"x\"\":1.100000023841858,\"\"y\"\":0.2441573292016983},{\"\"x\"\":1.600000023841858,\"\"y\"\":0.146635964512825},{\"\"x\"\":2.0999999046325684,\"\"y\"\":0.08818462491035461},{\"\"x\"\":2.5999999046325684,\"\"y\"\":0.2560656666755676},{\"\"x\"\":3.0999999046325684,\"\"y\"\":0.42434045672416687},{\"\"x\"\":3.5999999046325684,\"\"y\"\":0.37111231684684753},{\"\"x\"\":4.099999904632568,\"\"y\"\":0.5581737160682678},{\"\"x\"\":4.599999904632568,\"\"y\"\":1.183590054512024},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.5629843473434448},{\"\"x\"\":5.599999904632568,\"\"y\"\":2.3211288452148438},{\"\"x\"\":6.099999904632568,\"\"y\"\":2.229961633682251},{\"\"x\"\":6.599999904632568,\"\"y\"\":2.2560226917266846},{\"\"x\"\":7.099999904632568,\"\"y\"\":2.2142398357391357}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nCameroon,MIEVFLFGIVLGLIPITLAGLFVTAYLQYRRGDQLDL,COc1ccc2cc(ccc2c1)C(C)C(=O)OCCCc3cccnc3,1480016,36.26095962524414,995153596,30-56 WHITESTONE EXPY,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,3,3,2BDJ,3,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[4.6760652578642325, 0.9046956320756703, 5.651408971856738, 0.07738846012184185],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":4.32425594329834},{\"\"x\"\":0.6000000238418579,\"\"y\"\":4.668442249298096},{\"\"x\"\":1.100000023841858,\"\"y\"\":4.379785060882568},{\"\"x\"\":1.600000023841858,\"\"y\"\":5.0345139503479},{\"\"x\"\":2.0999999046325684,\"\"y\"\":4.878653526306152},{\"\"x\"\":2.5999999046325684,\"\"y\"\":4.3451313972473145},{\"\"x\"\":3.0999999046325684,\"\"y\"\":4.336992263793945},{\"\"x\"\":3.5999999046325684,\"\"y\"\":5.037430286407471},{\"\"x\"\":4.099999904632568,\"\"y\"\":5.0092692375183105},{\"\"x\"\":4.599999904632568,\"\"y\"\":4.151902675628662},{\"\"x\"\":5.099999904632568,\"\"y\"\":3.4066951274871826},{\"\"x\"\":5.599999904632568,\"\"y\"\":2.3732759952545166},{\"\"x\"\":6.099999904632568,\"\"y\"\":1.673728108406067},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.48574790358543396},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.2783052325248718}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[2.938395863010111, -1.4658480661392117, 5.462702751996584, 0.3473139023615039],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":0.4941710829734802},{\"\"x\"\":0.6000000238418579,\"\"y\"\":0.15323974192142487},{\"\"x\"\":1.100000023841858,\"\"y\"\":0.46373432874679565},{\"\"x\"\":1.600000023841858,\"\"y\"\":0.3370431363582611},{\"\"x\"\":2.0999999046325684,\"\"y\"\":0.5179030299186707},{\"\"x\"\":2.5999999046325684,\"\"y\"\":0.27899765968322754},{\"\"x\"\":3.0999999046325684,\"\"y\"\":0.22075064480304718},{\"\"x\"\":3.5999999046325684,\"\"y\"\":0.5789918899536133},{\"\"x\"\":4.099999904632568,\"\"y\"\":0.21169911324977875},{\"\"x\"\":4.599999904632568,\"\"y\"\":0.27857646346092224},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.0906332731246948},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.8520300388336182},{\"\"x\"\":6.099999904632568,\"\"y\"\":2.7177059650421143},{\"\"x\"\":6.599999904632568,\"\"y\"\":2.8680918216705322},{\"\"x\"\":7.099999904632568,\"\"y\"\":3.2413077354431152}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nCanada,MMELVLKTIIGPIVVGVVLRIVDKWLNKDK,CC(C(=O)NCCS)c1cccc(c1)C(=O)c2ccccc2,1480017,36.26095962524414,99515,30-56 WHITESTONE EXPY,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,4,4,1IAN,4,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[0.8597390975430008, 1.0957625732481946, 5.260537067987958, 0.07974187998177736],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":0.8190152645111084},{\"\"x\"\":0.6000000238418579,\"\"y\"\":0.8421689867973328},{\"\"x\"\":1.100000023841858,\"\"y\"\":0.8740922212600708},{\"\"x\"\":1.600000023841858,\"\"y\"\":0.8924275040626526},{\"\"x\"\":2.0999999046325684,\"\"y\"\":0.8249067664146423},{\"\"x\"\":2.5999999046325684,\"\"y\"\":0.9327669143676758},{\"\"x\"\":3.0999999046325684,\"\"y\"\":0.8522974252700806},{\"\"x\"\":3.5999999046325684,\"\"y\"\":0.8174492716789246},{\"\"x\"\":4.099999904632568,\"\"y\"\":0.8394647240638733},{\"\"x\"\":4.599999904632568,\"\"y\"\":0.7139387726783752},{\"\"x\"\":5.099999904632568,\"\"y\"\":0.5561167597770691},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.3276226818561554},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.12479474395513535},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.13006797432899475},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.059702079743146896}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[5.760930219582546, 1.6591793293833013, 4.667155929720851, 0.7858109544121652],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":6.156993389129639},{\"\"x\"\":0.6000000238418579,\"\"y\"\":5.236701965332031},{\"\"x\"\":1.100000023841858,\"\"y\"\":6.010560512542725},{\"\"x\"\":1.600000023841858,\"\"y\"\":5.495512962341309},{\"\"x\"\":2.0999999046325684,\"\"y\"\":6.087770462036133},{\"\"x\"\":2.5999999046325684,\"\"y\"\":5.79986572265625},{\"\"x\"\":3.0999999046325684,\"\"y\"\":5.597546577453613},{\"\"x\"\":3.5999999046325684,\"\"y\"\":5.520902156829834},{\"\"x\"\":4.099999904632568,\"\"y\"\":5.360654354095459},{\"\"x\"\":4.599999904632568,\"\"y\"\":3.5539746284484863},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.577236294746399},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.0001264810562134},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.9305797815322876},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.6033638715744019},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.4203685522079468}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nColombia,MDRTDEVSNHTHDKPTLTWFEEIFEEYHSPFHN,FC(F)(F)c1ccc(OC2CCNCC2)cc1,1480029,36.3309440612793,995152050,1 COURT HOUSE SQUARE,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,5,5,4UJ1,5,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[6.4995088314153655, 2.4270351004539914, 5.178659535348579, 0.625653346241577],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":6.496231555938721},{\"\"x\"\":0.6000000238418579,\"\"y\"\":6.42543363571167},{\"\"x\"\":1.100000023841858,\"\"y\"\":7.040063858032227},{\"\"x\"\":1.600000023841858,\"\"y\"\":6.1115403175354},{\"\"x\"\":2.0999999046325684,\"\"y\"\":6.680728435516357},{\"\"x\"\":2.5999999046325684,\"\"y\"\":6.406774520874023},{\"\"x\"\":3.0999999046325684,\"\"y\"\":6.611269474029541},{\"\"x\"\":3.5999999046325684,\"\"y\"\":5.889094352722168},{\"\"x\"\":4.099999904632568,\"\"y\"\":6.75344705581665},{\"\"x\"\":4.599999904632568,\"\"y\"\":6.361435890197754},{\"\"x\"\":5.099999904632568,\"\"y\"\":4.1666975021362305},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.172118902206421},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.801048994064331},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.4640021026134491},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.0010357667924836278}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[1.4734381347446401, 1.1649805188074196, 4.82958608866421, 0.09500545496710007],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":1.5279096364974976},{\"\"x\"\":0.6000000238418579,\"\"y\"\":1.3559974431991577},{\"\"x\"\":1.100000023841858,\"\"y\"\":1.5246378183364868},{\"\"x\"\":1.600000023841858,\"\"y\"\":1.5567657947540283},{\"\"x\"\":2.0999999046325684,\"\"y\"\":1.4114240407943726},{\"\"x\"\":2.5999999046325684,\"\"y\"\":1.4045010805130005},{\"\"x\"\":3.0999999046325684,\"\"y\"\":1.4769829511642456},{\"\"x\"\":3.5999999046325684,\"\"y\"\":1.4875500202178955},{\"\"x\"\":4.099999904632568,\"\"y\"\":1.2991987466812134},{\"\"x\"\":4.599999904632568,\"\"y\"\":0.922961413860321},{\"\"x\"\":5.099999904632568,\"\"y\"\":0.6520044803619385},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.15350978076457977},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.1078903079032898},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.17276449501514435},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.14066608250141144}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nCosta Rica,MKSTKEEIQTIKTLLKDSRTAKYHKRLQIVL,CC(C)Cc1ccc(cc1)C(C)C(=O)N2CCCC2C(=O)OCCCc3ccccc3,1480018,36.3309440612793,995084218,4041 SOUTHWESTERN BLVD,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,6,6,2BPW,6,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[2.4833641843311227, -1.8945978742090062, 4.671127708092568, 0.24159861311815153],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":0.0969524160027504},{\"\"x\"\":0.6000000238418579,\"\"y\"\":0.028483040630817413},{\"\"x\"\":1.100000023841858,\"\"y\"\":0.22087176144123077},{\"\"x\"\":1.600000023841858,\"\"y\"\":0.0068915546871721745},{\"\"x\"\":2.0999999046325684,\"\"y\"\":0.4305879771709442},{\"\"x\"\":2.5999999046325684,\"\"y\"\":0.44774115085601807},{\"\"x\"\":3.0999999046325684,\"\"y\"\":0.45346319675445557},{\"\"x\"\":3.5999999046325684,\"\"y\"\":0.2370593100786209},{\"\"x\"\":4.099999904632568,\"\"y\"\":0.4657953977584839},{\"\"x\"\":4.599999904632568,\"\"y\"\":1.155200719833374},{\"\"x\"\":5.099999904632568,\"\"y\"\":2.2294070720672607},{\"\"x\"\":5.599999904632568,\"\"y\"\":2.4311530590057373},{\"\"x\"\":6.099999904632568,\"\"y\"\":2.33846116065979},{\"\"x\"\":6.599999904632568,\"\"y\"\":2.608201026916504},{\"\"x\"\":7.099999904632568,\"\"y\"\":2.8136143684387207}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[5.224573521642033, 1.4454033924198528, 5.6014197746076535, 0.2823216054197577],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":4.95027494430542},{\"\"x\"\":0.6000000238418579,\"\"y\"\":5.1754679679870605},{\"\"x\"\":1.100000023841858,\"\"y\"\":5.276752948760986},{\"\"x\"\":1.600000023841858,\"\"y\"\":5.589294910430908},{\"\"x\"\":2.0999999046325684,\"\"y\"\":5.616994857788086},{\"\"x\"\":2.5999999046325684,\"\"y\"\":5.120813846588135},{\"\"x\"\":3.0999999046325684,\"\"y\"\":5.340766906738281},{\"\"x\"\":3.5999999046325684,\"\"y\"\":4.876471042633057},{\"\"x\"\":4.099999904632568,\"\"y\"\":4.94999361038208},{\"\"x\"\":4.599999904632568,\"\"y\"\":5.162564754486084},{\"\"x\"\":5.099999904632568,\"\"y\"\":4.399557590484619},{\"\"x\"\":5.599999904632568,\"\"y\"\":2.7977969646453857},{\"\"x\"\":6.099999904632568,\"\"y\"\":1.0229872465133667},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.48275601863861084},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.10408931970596313}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nCuba,MHAILRYFIRRLFYHIFYKIYSLISKKHQSLPSDVRQF,COc1ccc2c(c1)c(CC(=O)N3CCCC3C(=O)Oc4ccc(C)cc4OC)c(C)n2C(=O)c5ccc(Cl)cc5,1480019,36.33115768432617,995081928,1227 US HIGHWAY 11,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,7,7,1QBS,7,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[3.320838679713925, -1.2421619987316728, 4.831325425225256, 0.3236011098403072],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":0.3727470338344574},{\"\"x\"\":0.6000000238418579,\"\"y\"\":0.12365014106035233},{\"\"x\"\":1.100000023841858,\"\"y\"\":0.48422467708587646},{\"\"x\"\":1.600000023841858,\"\"y\"\":0.2264465093612671},{\"\"x\"\":2.0999999046325684,\"\"y\"\":0.16821794211864471},{\"\"x\"\":2.5999999046325684,\"\"y\"\":0.3879014551639557},{\"\"x\"\":3.0999999046325684,\"\"y\"\":0.5470244884490967},{\"\"x\"\":3.5999999046325684,\"\"y\"\":0.3419053554534912},{\"\"x\"\":4.099999904632568,\"\"y\"\":0.7655120491981506},{\"\"x\"\":4.599999904632568,\"\"y\"\":1.2346516847610474},{\"\"x\"\":5.099999904632568,\"\"y\"\":2.453336715698242},{\"\"x\"\":5.599999904632568,\"\"y\"\":2.9565491676330566},{\"\"x\"\":6.099999904632568,\"\"y\"\":3.335299491882324},{\"\"x\"\":6.599999904632568,\"\"y\"\":3.240290880203247},{\"\"x\"\":7.099999904632568,\"\"y\"\":3.1107218265533447}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[3.6401853521511094, 1.26211588875013, 5.399028074402744, 0.5089580830068091],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":3.8585598468780518},{\"\"x\"\":0.6000000238418579,\"\"y\"\":3.6077206134796143},{\"\"x\"\":1.100000023841858,\"\"y\"\":3.855252265930176},{\"\"x\"\":1.600000023841858,\"\"y\"\":3.619039297103882},{\"\"x\"\":2.0999999046325684,\"\"y\"\":3.839388370513916},{\"\"x\"\":2.5999999046325684,\"\"y\"\":3.335283041000366},{\"\"x\"\":3.0999999046325684,\"\"y\"\":3.571141481399536},{\"\"x\"\":3.5999999046325684,\"\"y\"\":3.4155046939849854},{\"\"x\"\":4.099999904632568,\"\"y\"\":3.7316646575927734},{\"\"x\"\":4.599999904632568,\"\"y\"\":3.0680155754089355},{\"\"x\"\":5.099999904632568,\"\"y\"\":2.891066551208496},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.6022753715515137},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.7652576565742493},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.6875326037406921},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.5828871726989746}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nItaly,MSNFHNEHVMQFYRNNLKTKGVFGRQ,CC(C)Cc1ccc(cc1)C(C)C(=O)N2CCCC2C(=O)OCCO[N+](=O)[O-],1480020,36.33115768432617,99502,\"168-46 91ST AVE., 2ND FLR\",https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,8,8,1ZP8,8,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[2.293592105923809, 1.3781586549141835, 5.1025898038676605, 0.03493851245291291],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":2.1287283897399902},{\"\"x\"\":0.6000000238418579,\"\"y\"\":2.267972230911255},{\"\"x\"\":1.100000023841858,\"\"y\"\":2.398442506790161},{\"\"x\"\":1.600000023841858,\"\"y\"\":2.5130622386932373},{\"\"x\"\":2.0999999046325684,\"\"y\"\":2.3255116939544678},{\"\"x\"\":2.5999999046325684,\"\"y\"\":2.127340793609619},{\"\"x\"\":3.0999999046325684,\"\"y\"\":2.47259783744812},{\"\"x\"\":3.5999999046325684,\"\"y\"\":2.131181478500366},{\"\"x\"\":4.099999904632568,\"\"y\"\":2.090421438217163},{\"\"x\"\":4.599999904632568,\"\"y\"\":2.02299165725708},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.1105059385299683},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.4494485855102539},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.1375635862350464},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.036351121962070465},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.1619771122932434}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[5.953125499439879, 1.2528620255306528, 5.187637440149802, 0.3110348753260886],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":5.6585283279418945},{\"\"x\"\":0.6000000238418579,\"\"y\"\":5.911152362823486},{\"\"x\"\":1.100000023841858,\"\"y\"\":5.924920082092285},{\"\"x\"\":1.600000023841858,\"\"y\"\":5.8469438552856445},{\"\"x\"\":2.0999999046325684,\"\"y\"\":5.929472923278809},{\"\"x\"\":2.5999999046325684,\"\"y\"\":6.190037727355957},{\"\"x\"\":3.0999999046325684,\"\"y\"\":6.236179828643799},{\"\"x\"\":3.5999999046325684,\"\"y\"\":6.141019344329834},{\"\"x\"\":4.099999904632568,\"\"y\"\":5.295210838317871},{\"\"x\"\":4.599999904632568,\"\"y\"\":5.265801906585693},{\"\"x\"\":5.099999904632568,\"\"y\"\":3.3722851276397705},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.8299226760864258},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.32690900564193726},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.6274543404579163},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.8441857099533081}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nRwanda,MPNSEPASLLELFNSIATQGELVRSLKAGNASK,CC(C)Cc1ccc(cc1)C(C)C(=O)N2CCCC2C(=O)OCCO,1480021,36.33137130737305,995037247,\"168-46 91ST AVE., 2ND FLR\",https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,9,9,2BDJ,9,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[3.8209972202654474, 1.3779216716448506, 5.299882228439686, 0.06040645519069608],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":3.7821109294891357},{\"\"x\"\":0.6000000238418579,\"\"y\"\":3.542433023452759},{\"\"x\"\":1.100000023841858,\"\"y\"\":3.7008674144744873},{\"\"x\"\":1.600000023841858,\"\"y\"\":3.717301607131958},{\"\"x\"\":2.0999999046325684,\"\"y\"\":4.024452209472656},{\"\"x\"\":2.5999999046325684,\"\"y\"\":4.013899326324463},{\"\"x\"\":3.0999999046325684,\"\"y\"\":3.945094347000122},{\"\"x\"\":3.5999999046325684,\"\"y\"\":3.866621971130371},{\"\"x\"\":4.099999904632568,\"\"y\"\":3.7461626529693604},{\"\"x\"\":4.599999904632568,\"\"y\"\":3.3454740047454834},{\"\"x\"\":5.099999904632568,\"\"y\"\":2.61944317817688},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.999405026435852},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.46259793639183044},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.054134611040353775},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.05711187422275543}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[5.6318079657726035, 1.8495493770000595, 5.391793312471116, 0.17060707587348442],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":5.458079814910889},{\"\"x\"\":0.6000000238418579,\"\"y\"\":5.554427146911621},{\"\"x\"\":1.100000023841858,\"\"y\"\":5.799983024597168},{\"\"x\"\":1.600000023841858,\"\"y\"\":5.364140033721924},{\"\"x\"\":2.0999999046325684,\"\"y\"\":5.864485740661621},{\"\"x\"\":2.5999999046325684,\"\"y\"\":5.4509806632995605},{\"\"x\"\":3.0999999046325684,\"\"y\"\":5.702574729919434},{\"\"x\"\":3.5999999046325684,\"\"y\"\":5.7314534187316895},{\"\"x\"\":4.099999904632568,\"\"y\"\":5.5123443603515625},{\"\"x\"\":4.599999904632568,\"\"y\"\":5.724395751953125},{\"\"x\"\":5.099999904632568,\"\"y\"\":4.354506969451904},{\"\"x\"\":5.599999904632568,\"\"y\"\":1.7307666540145874},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.6305936574935913},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.035183437168598175},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.7575169205665588}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\nSwitzerland,IRVVGRYLIEVWKAAGMDMDKVLFLWSSDEI,CN1CCC(CC1)Oc2ccc(cc2)C(F)(F)F,1480028,36.33137130737305,99504,92-11 179TH PLACE,https://datagrok.ai/img/slides/access-db-connect.png,id,ErrorMessage,\"COMPND \nATOM \nEND\",flag,9,10,1IAN,10,1.23,<chart></chart>,\"{\"\"series\"\":[{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitFunction\"\":\"\"sigmoid\"\",\"\"fitLineColor\"\":\"\"#1f77b4\"\",\"\"pointColor\"\":\"\"#1f77b4\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[1.1190255865097471, 2.3163895161544437, 5.4968866182279195, 0.2035204047289052],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":1.1057683229446411},{\"\"x\"\":0.6000000238418579,\"\"y\"\":1.1019697189331055},{\"\"x\"\":1.100000023841858,\"\"y\"\":1.0818607807159424},{\"\"x\"\":1.600000023841858,\"\"y\"\":1.062997817993164},{\"\"x\"\":2.0999999046325684,\"\"y\"\":1.046447515487671},{\"\"x\"\":2.5999999046325684,\"\"y\"\":1.1217249631881714},{\"\"x\"\":3.0999999046325684,\"\"y\"\":1.2166996002197266},{\"\"x\"\":3.5999999046325684,\"\"y\"\":1.215477705001831},{\"\"x\"\":4.099999904632568,\"\"y\"\":1.0581893920898438},{\"\"x\"\":4.599999904632568,\"\"y\"\":1.1747995615005493},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.0181127786636353},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.5344523191452026},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.2569526433944702},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.1912207305431366},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.15060538053512573}]},{\"\"name\"\":\"\"Run:2023-08-08\"\",\"\"fitLineColor\"\":\"\"#ffbb78\"\",\"\"pointColor\"\":\"\"#ffbb78\"\",\"\"showPoints\"\":\"\"points\"\",\"\"parameters\"\":[3.1038581025805785, 2.0032224204185245, 5.087602825989163, 0.13277988512492753],\"\"points\"\":[{\"\"x\"\":0.10000000149011612,\"\"y\"\":3.0498509407043457},{\"\"x\"\":0.6000000238418579,\"\"y\"\":2.805217742919922},{\"\"x\"\":1.100000023841858,\"\"y\"\":3.3415253162384033},{\"\"x\"\":1.600000023841858,\"\"y\"\":3.0549843311309814},{\"\"x\"\":2.0999999046325684,\"\"y\"\":3.250074863433838},{\"\"x\"\":2.5999999046325684,\"\"y\"\":3.0432586669921875},{\"\"x\"\":3.0999999046325684,\"\"y\"\":3.265852451324463},{\"\"x\"\":3.5999999046325684,\"\"y\"\":2.9475724697113037},{\"\"x\"\":4.099999904632568,\"\"y\"\":3.1929898262023926},{\"\"x\"\":4.599999904632568,\"\"y\"\":2.7460060119628906},{\"\"x\"\":5.099999904632568,\"\"y\"\":1.6175861358642578},{\"\"x\"\":5.599999904632568,\"\"y\"\":0.3006608486175537},{\"\"x\"\":6.099999904632568,\"\"y\"\":0.3444803059101105},{\"\"x\"\":6.599999904632568,\"\"y\"\":0.015537971630692482},{\"\"x\"\":7.099999904632568,\"\"y\"\":0.5527358055114746}]}],\"\"chartOptions\"\":{\"\"xAxisName\"\":\"\"Conc.\"\",\"\"yAxisName\"\":\"\"Activity\"\",\"\"title\"\":\"\"Dose-Response curves\"\"}}\",text,,\n,,,,,,,,,,,,,,,,,,,,,`);\ntestData.columns.add(DG.Column.fromList(DG.TYPE.BYTE_ARRAY, 'BinaryImage', Array.from(new Uint8Array(11))));\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWZyYW1lLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGF0YWZyYW1lLXV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE9BQU8sS0FBSyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ3RDOzs7R0FHRztBQUNILE1BQU0sVUFBVSxxQkFBcUIsQ0FBQyxLQUFvQixFQUFFLEdBQWU7SUFDekUsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLFVBQVUsQ0FBQztJQUM1QixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEtBQUssSUFBSSxDQUFDLENBQUM7SUFDMUYsTUFBTSxPQUFPLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQ3RDLE1BQU0sZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO0lBQzVCLElBQUksa0JBQWtCLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3ZDLElBQUksV0FBVyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUNwQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUcsa0JBQWtCLENBQUMsQ0FBQztZQUM1QyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekIsa0JBQWtCLElBQUksQ0FBQyxDQUFDO1NBQ3pCO0tBQ0Y7SUFDRCxPQUFPLGdCQUFnQixDQUFDO0FBQzFCLENBQUM7QUFFRCxNQUFNLFVBQVUsYUFBYSxDQUFDLEtBQW9CLEVBQUUsS0FBZ0I7SUFDbEUsS0FBSyxhQUFMLEtBQUssY0FBTCxLQUFLLElBQUwsS0FBSyxHQUFLLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUM7SUFDaEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDakMsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMxQyxNQUFNLE9BQU8sR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO0lBQ2xDLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFO1FBQ3hCLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFDLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUN0QyxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQy9DLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFDL0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDekMsSUFBSSxRQUFRLEVBQUU7Z0JBQ1osTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN2QyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzthQUNyQztpQkFBTTtnQkFDTCxNQUFNLElBQUksR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ2pDLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUN4QztTQUNGO0tBQ0Y7SUFDRCxPQUFPLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUN6QixDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O3NCQStCdkIsQ0FBQyxDQUFDO0FBQ3hCLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLGFBQWEsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuaW1wb3J0IHR5cGUgKiBhcyBfREcgZnJvbSAnZGF0YWdyb2stYXBpL2RnJztcbmRlY2xhcmUgbGV0IERHOiB0eXBlb2YgX0RHO1xuaW1wb3J0ICogYXMgc2hhMjU2IGZyb20gJ2Zhc3Qtc2hhMjU2Jztcbi8qKlxuICogRm9yIGNvbHVtbnMgb2Ygc3RyaW5nIHR5cGUuIENoZWNrcyB3aGV0aGVyIGNvbHVtbiBjb250YWlucyBlbXB0eSB2YWx1ZXMgYW5kIHJlbW92ZXMgY29ycmVzcG9uZGluZyByb3dzIGluIGNhc2UgdXNlciBzZWxlY3RzIHRvIHJlbW92ZS5cbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZW1vdmVFbXB0eVN0cmluZ1Jvd3ModGFibGU6IF9ERy5EYXRhRnJhbWUsIGNvbDogX0RHLkNvbHVtbik6IG51bWJlcltdIHtcbiAgY29uc3QgY2F0cyA9IGNvbC5jYXRlZ29yaWVzO1xuICBjb25zdCBlbXB0eVJhd0luZCA9IGNhdHMubWFwKCh2YWwsIGluZCkgPT4gIXZhbCA/IGluZCA6IG51bGwpLmZpbHRlcigoaXQpID0+IGl0ICE9PSBudWxsKTtcbiAgY29uc3QgcmF3RGF0YSA9IFsuLi5jb2wuZ2V0UmF3RGF0YSgpXTtcbiAgY29uc3QgZW1wdHlSYXdzSW5kZXhlcyA9IFtdO1xuICBsZXQgcmVtb3ZlZFJvd3NDb3VudGVyID0gMDtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB0YWJsZS5yb3dDb3VudDsgaSsrKSB7XG4gICAgaWYgKGVtcHR5UmF3SW5kLmluY2x1ZGVzKHJhd0RhdGFbaV0pKSB7XG4gICAgICB0YWJsZS5yb3dzLnJlbW92ZUF0KGkgLSByZW1vdmVkUm93c0NvdW50ZXIpO1xuICAgICAgZW1wdHlSYXdzSW5kZXhlcy5wdXNoKGkpO1xuICAgICAgcmVtb3ZlZFJvd3NDb3VudGVyICs9IDE7XG4gICAgfVxuICB9XG4gIHJldHVybiBlbXB0eVJhd3NJbmRleGVzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaGFzaERhdGFGcmFtZSh0YWJsZTogX0RHLkRhdGFGcmFtZSwgbmFtZXM/OiBzdHJpbmdbXSk6IFVpbnQ4QXJyYXkge1xuICBuYW1lcyA/Pz0gdGFibGUuY29sdW1ucy5uYW1lcygpO1xuICBjb25zdCBoYXNoZXIgPSBuZXcgc2hhMjU2Lkhhc2goKTtcbiAgY29uc3Qgb3JkZXIgPSB0YWJsZS5nZXRTb3J0ZWRPcmRlcihuYW1lcyk7XG4gIGNvbnN0IGVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgZm9yIChjb25zdCBuYW1lIG9mIG5hbWVzKSB7XG4gICAgY29uc3QgY29sdW1uID0gdGFibGUuY29sdW1ucy5ieU5hbWUobmFtZSk7XG4gICAgY29uc3QgZGF0YUFycmF5ID0gY29sdW1uLmdldFJhd0RhdGEoKTtcbiAgICBjb25zdCBpc1N0cmluZyA9IGNvbHVtbi50eXBlID09IERHLlRZUEUuU1RSSU5HO1xuICAgIGNvbnN0IGNhdHMgPSBjb2x1bW4uY2F0ZWdvcmllcztcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRhdGFBcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGlzU3RyaW5nKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBjYXRzW2RhdGFBcnJheVtvcmRlcltpXV1dO1xuICAgICAgICBoYXNoZXIudXBkYXRlKGVuY29kZXIuZW5jb2RlKGRhdGEpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBkYXRhQXJyYXlbb3JkZXJbaV1dO1xuICAgICAgICBoYXNoZXIudXBkYXRlKFVpbnQ4QXJyYXkuZnJvbShbZGF0YV0pKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGhhc2hlci5kaWdlc3QoKTtcbn1cblxuZXhwb3J0IGNvbnN0IHRlc3REYXRhID0gREcuRGF0YUZyYW1lLmZyb21Dc3YoYGNvdW50cmllcyxmYXN0YSxzbWlsZXMsbW9scmVnbm8sTE9OLFppcCBDb2RlLFN0cmVldCBBZGRyZXNzIExpbmUgMSxJbWFnZVVybCx1c2VyX2lkLGVycm9yX21lc3NhZ2UseHJheSxmbGFnLG1hZ25pdHVkZSxDUy1pZCxwZGJfaWQsYWNjZWxfYSx0aW1lX29mZnNldCxjaGFydCxmaXQsUXVlc3Rpb25zLGVtcHR5X251bWJlcixlbXB0eV9zdHJpbmdcbkJlbGdpdW0sTVNORkhORUhWTVFGWVJOTkxLVEtHVkZHUlEsQ0MoQyg9TylPQ0NDYzFjY2NuYzEpYzJjY2NjKGMyKUMoPU8pYzNjY2NjYzMsMTQ4MDAxNCwzNi4yNzY3Mjk1ODM3NDAyMzQsOTk1MDQyMzAwLDE0MDE2IFJPVVRFIDMxVyxodHRwczovL2RhdGFncm9rLmFpL2ltZy9zbGlkZXMvYWNjZXNzLWRiLWNvbm5lY3QucG5nLGlkLEVycm9yTWVzc2FnZSxcIkNPTVBORCBcbkFUT00gXG5FTkRcIixmbGFnLDEsMSwxUUJTLDEsMS4yMyw8Y2hhcnQ+PC9jaGFydD4sXCJ7XCJcInNlcmllc1wiXCI6W3tcIlwibmFtZVwiXCI6XCJcIlJ1bjoyMDIzLTA4LTA4XCJcIixcIlwiZml0RnVuY3Rpb25cIlwiOlwiXCJzaWdtb2lkXCJcIixcIlwiZml0TGluZUNvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInBvaW50Q29sb3JcIlwiOlwiXCIjMWY3N2I0XCJcIixcIlwic2hvd1BvaW50c1wiXCI6XCJcInBvaW50c1wiXCIsXCJcInBhcmFtZXRlcnNcIlwiOlsyLjQ5NzM2MDM0MDY0NDg3MiwgMS43MDU4Njk0OTg2Njg2ODY0LCA1LjI3ODA1MjY3ODE5NTEzNSwgMC4xNjAwMDMyMDg4OTAyODM4M10sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6Mi4zNzQ0OTk3OTc4MjEwNDV9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjoyLjYyNDI0NzMxMjU0NTc3NjR9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjIuMzY3MjY3NjA4NjQyNTc4fSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjoyLjY3MjMxNDg4MjI3ODQ0MjR9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoyLjY1MzczNDQ0NTU3MTg5OTR9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoyLjM2NTE2NzE0MDk2MDY5MzR9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoyLjU2NTQyODQ5NTQwNzEwNDV9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoyLjQxNjA5NTk3MjA2MTE1NzJ9LHtcIlwieFwiXCI6NC4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuMjg2NzI2NzEzMTgwNTQyfSx7XCJcInhcIlwiOjQuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjUxMDAwNDI4MTk5NzY4MDd9LHtcIlwieFwiXCI6NS4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuNjY3Njk4NTAyNTQwNTg4NH0se1wiXCJ4XCJcIjo1LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC42ODAxMzY1MDE3ODkwOTN9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMzM5MTU0MzkyNDgwODUwMn0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4wOTAzODk4MzI4NTQyNzA5NH0se1wiXCJ4XCJcIjo3LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4xOTgwMjc3NTk3OTA0MjA1M31dfSx7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbNy41MjUyMzU4NTU1MDgxNzksIDEuMzE4NjkxMTg3NjgwOTk4NCwgNS4zMzU2NzI2MDg1NjQyOTQsIDAuNzg2MDc0MzM0Mzk1ODA5OF0sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6Ny45ODgwNzA0ODc5NzYwNzR9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjo3LjAxODQ1MzEyMTE4NTMwM30se1wiXCJ4XCJcIjoxLjEwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6OC4xMTUyNzkxOTc2OTI4NzF9LHtcIlwieFwiXCI6MS42MDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjcuNDg2NjU4MDk2MzEzNDc3fSx7XCJcInhcIlwiOjIuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6Ny4zOTY0MzgxMjE3OTU2NTR9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo3LjQ3NzA1MjIxMTc2MTQ3NX0se1wiXCJ4XCJcIjozLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjYuOTEzMDk1NDc0MjQzMTY0fSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6OC4wMTM4NTQ5ODA0Njg3NX0se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Ni45ODU5MDA0MDIwNjkwOTJ9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjYuOTcwMzM1OTYwMzg4MTg0fSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjo1LjQ0ODgxNzI1MzExMjc5M30se1wiXCJ4XCJcIjo1LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Mi41NTM0ODE4MTcyNDU0ODM0fSx7XCJcInhcIlwiOjYuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjg5Mzk0Nzk1ODk0NjIyOH0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC42MzQwMDQyMzUyNjc2MzkyfSx7XCJcInhcIlwiOjcuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjg0MDM4NzQwMzk2NDk5NjN9XX1dLFwiXCJjaGFydE9wdGlvbnNcIlwiOntcIlwieEF4aXNOYW1lXCJcIjpcIlwiQ29uYy5cIlwiLFwiXCJ5QXhpc05hbWVcIlwiOlwiXCJBY3Rpdml0eVwiXCIsXCJcInRpdGxlXCJcIjpcIlwiRG9zZS1SZXNwb25zZSBjdXJ2ZXNcIlwifX1cIix0ZXh0LDEwMCxhYmNcbkJ1cnVuZGksTURZS0VUTExNUEtUREZQTVJHR0xQTktFUFFJUUVLVyxDT2MxY2NjMmNjKGNjYzJjMSlDKEMpQyg9TylPYzNjY2MoQyljYzNPQywxNDgwMDE1LDM2LjI3NjcyOTU4Mzc0MDIzNCw5OTUwNzM0NDQsODAgU1RBVEUgSElHSFdBWSAzMTAsaHR0cHM6Ly9kYXRhZ3Jvay5haS9pbWcvc2xpZGVzL2FjY2Vzcy1kYi1jb25uZWN0LnBuZyxpZCxFcnJvck1lc3NhZ2UsXCJDT01QTkQgXG5BVE9NIFxuRU5EXCIsZmxhZywyLDIsMVpQOCwyLDEuMjMsPGNoYXJ0PjwvY2hhcnQ+LFwie1wiXCJzZXJpZXNcIlwiOlt7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdEZ1bmN0aW9uXCJcIjpcIlwic2lnbW9pZFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbNC40MzE0NjA3NTMxMDMzOTgsIDIuMTY5MTQ5ODc5OTI0Njc0NSwgNS4yNjY0NDU1OTcxMDI3NzQsIDAuNzgyNTc2MjgyNzAxNzkyNl0sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6NC43NTEwODM4NTA4NjA1OTZ9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjo0LjIwMzAwMDA2ODY2NDU1MX0se1wiXCJ4XCJcIjoxLjEwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6NC40MTU4NTg3NDU1NzQ5NTF9LHtcIlwieFwiXCI6MS42MDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjQuNjg0MTQzMDY2NDA2MjV9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo0LjE5ODQwMDk3NDI3MzY4Mn0se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjQuMTc5MjIyMTA2OTMzNTk0fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NC42Mzg0NzM5ODc1NzkzNDZ9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo0LjcwODU1MzMxNDIwODk4NH0se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6NC4yOTE1ODkyNjAxMDEzMTh9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjQuMDM4MDgyNTk5NjM5ODkzfSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjQzNDk5Mzk4MjMxNTA2MzV9LHtcIlwieFwiXCI6NS41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuMjE5NDcwODU4NTczOTEzNn0se1wiXCJ4XCJcIjo2LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS4xOTIwODMxMjAzNDYwNjkzfSx7XCJcInhcIlwiOjYuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjUzNTI2MzU5Nzk2NTI0MDV9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMzM0NjkyMDMxMTQ1MDk1OH1dfSx7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMi4zMzk0NTgwMTc5NzAxMjYsIC0xLjA3MzQxODQzMTAxNzExNzgsIDQuNzQ2MzMyOTUwNTUwOTM0LCAwLjI0ODI0MTY4NTc1OTU2NThdLFwiXCJwb2ludHNcIlwiOlt7XCJcInhcIlwiOjAuMTAwMDAwMDAxNDkwMTE2MTIsXCJcInlcIlwiOjAuMjEzOTMzNzY1ODg4MjE0MX0se1wiXCJ4XCJcIjowLjYwMDAwMDAyMzg0MTg1NzksXCJcInlcIlwiOjAuNDI2OTU2MjA2NTYwMTM0OX0se1wiXCJ4XCJcIjoxLjEwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6MC4yNDQxNTczMjkyMDE2OTgzfSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjowLjE0NjYzNTk2NDUxMjgyNX0se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjAuMDg4MTg0NjI0OTEwMzU0NjF9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjI1NjA2NTY2NjY3NTU2NzZ9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjQyNDM0MDQ1NjcyNDE2Njg3fSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC4zNzExMTIzMTY4NDY4NDc1M30se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC41NTgxNzM3MTYwNjgyNjc4fSx7XCJcInhcIlwiOjQuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjE4MzU5MDA1NDUxMjAyNH0se1wiXCJ4XCJcIjo1LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS41NjI5ODQzNDczNDM0NDQ4fSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjMyMTEyODg0NTIxNDg0Mzh9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuMjI5OTYxNjMzNjgyMjUxfSx7XCJcInhcIlwiOjYuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjI1NjAyMjY5MTcyNjY4NDZ9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuMjE0MjM5ODM1NzM5MTM1N31dfV0sXCJcImNoYXJ0T3B0aW9uc1wiXCI6e1wiXCJ4QXhpc05hbWVcIlwiOlwiXCJDb25jLlwiXCIsXCJcInlBeGlzTmFtZVwiXCI6XCJcIkFjdGl2aXR5XCJcIixcIlwidGl0bGVcIlwiOlwiXCJEb3NlLVJlc3BvbnNlIGN1cnZlc1wiXCJ9fVwiLHRleHQsLFxuQ2FtZXJvb24sTUlFVkZMRkdJVkxHTElQSVRMQUdMRlZUQVlMUVlSUkdEUUxETCxDT2MxY2NjMmNjKGNjYzJjMSlDKEMpQyg9TylPQ0NDYzNjY2NuYzMsMTQ4MDAxNiwzNi4yNjA5NTk2MjUyNDQxNCw5OTUxNTM1OTYsMzAtNTYgV0hJVEVTVE9ORSBFWFBZLGh0dHBzOi8vZGF0YWdyb2suYWkvaW1nL3NsaWRlcy9hY2Nlc3MtZGItY29ubmVjdC5wbmcsaWQsRXJyb3JNZXNzYWdlLFwiQ09NUE5EIFxuQVRPTSBcbkVORFwiLGZsYWcsMywzLDJCREosMywxLjIzLDxjaGFydD48L2NoYXJ0PixcIntcIlwic2VyaWVzXCJcIjpbe1wiXCJuYW1lXCJcIjpcIlwiUnVuOjIwMjMtMDgtMDhcIlwiLFwiXCJmaXRGdW5jdGlvblwiXCI6XCJcInNpZ21vaWRcIlwiLFwiXCJmaXRMaW5lQ29sb3JcIlwiOlwiXCIjMWY3N2I0XCJcIixcIlwicG9pbnRDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJzaG93UG9pbnRzXCJcIjpcIlwicG9pbnRzXCJcIixcIlwicGFyYW1ldGVyc1wiXCI6WzQuNjc2MDY1MjU3ODY0MjMyNSwgMC45MDQ2OTU2MzIwNzU2NzAzLCA1LjY1MTQwODk3MTg1NjczOCwgMC4wNzczODg0NjAxMjE4NDE4NV0sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6NC4zMjQyNTU5NDMyOTgzNH0se1wiXCJ4XCJcIjowLjYwMDAwMDAyMzg0MTg1NzksXCJcInlcIlwiOjQuNjY4NDQyMjQ5Mjk4MDk2fSx7XCJcInhcIlwiOjEuMTAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjo0LjM3OTc4NTA2MDg4MjU2OH0se1wiXCJ4XCJcIjoxLjYwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6NS4wMzQ1MTM5NTAzNDc5fSx7XCJcInhcIlwiOjIuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NC44Nzg2NTM1MjYzMDYxNTJ9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo0LjM0NTEzMTM5NzI0NzMxNDV9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo0LjMzNjk5MjI2Mzc5Mzk0NX0se1wiXCJ4XCJcIjozLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjUuMDM3NDMwMjg2NDA3NDcxfSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjo1LjAwOTI2OTIzNzUxODMxMDV9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjQuMTUxOTAyNjc1NjI4NjYyfSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjQwNjY5NTEyNzQ4NzE4MjZ9LHtcIlwieFwiXCI6NS41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuMzczMjc1OTk1MjU0NTE2Nn0se1wiXCJ4XCJcIjo2LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS42NzM3MjgxMDg0MDYwNjd9LHtcIlwieFwiXCI6Ni41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNDg1NzQ3OTAzNTg1NDMzOTZ9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMjc4MzA1MjMyNTI0ODcxOH1dfSx7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMi45MzgzOTU4NjMwMTAxMTEsIC0xLjQ2NTg0ODA2NjEzOTIxMTcsIDUuNDYyNzAyNzUxOTk2NTg0LCAwLjM0NzMxMzkwMjM2MTUwMzldLFwiXCJwb2ludHNcIlwiOlt7XCJcInhcIlwiOjAuMTAwMDAwMDAxNDkwMTE2MTIsXCJcInlcIlwiOjAuNDk0MTcxMDgyOTczNDgwMn0se1wiXCJ4XCJcIjowLjYwMDAwMDAyMzg0MTg1NzksXCJcInlcIlwiOjAuMTUzMjM5NzQxOTIxNDI0ODd9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjAuNDYzNzM0MzI4NzQ2Nzk1NjV9LHtcIlwieFwiXCI6MS42MDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjAuMzM3MDQzMTM2MzU4MjYxMX0se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjAuNTE3OTAzMDI5OTE4NjcwN30se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjAuMjc4OTk3NjU5NjgzMjI3NTR9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjIyMDc1MDY0NDgwMzA0NzE4fSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC41Nzg5OTE4ODk5NTM2MTMzfSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjIxMTY5OTExMzI0OTc3ODc1fSx7XCJcInhcIlwiOjQuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjI3ODU3NjQ2MzQ2MDkyMjI0fSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjA5MDYzMzI3MzEyNDY5NDh9LHtcIlwieFwiXCI6NS41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuODUyMDMwMDM4ODMzNjE4Mn0se1wiXCJ4XCJcIjo2LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Mi43MTc3MDU5NjUwNDIxMTQzfSx7XCJcInhcIlwiOjYuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjg2ODA5MTgyMTY3MDUzMjJ9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjMuMjQxMzA3NzM1NDQzMTE1Mn1dfV0sXCJcImNoYXJ0T3B0aW9uc1wiXCI6e1wiXCJ4QXhpc05hbWVcIlwiOlwiXCJDb25jLlwiXCIsXCJcInlBeGlzTmFtZVwiXCI6XCJcIkFjdGl2aXR5XCJcIixcIlwidGl0bGVcIlwiOlwiXCJEb3NlLVJlc3BvbnNlIGN1cnZlc1wiXCJ9fVwiLHRleHQsLFxuQ2FuYWRhLE1NRUxWTEtUSUlHUElWVkdWVkxSSVZES1dMTktESyxDQyhDKD1PKU5DQ1MpYzFjY2NjKGMxKUMoPU8pYzJjY2NjYzIsMTQ4MDAxNywzNi4yNjA5NTk2MjUyNDQxNCw5OTUxNSwzMC01NiBXSElURVNUT05FIEVYUFksaHR0cHM6Ly9kYXRhZ3Jvay5haS9pbWcvc2xpZGVzL2FjY2Vzcy1kYi1jb25uZWN0LnBuZyxpZCxFcnJvck1lc3NhZ2UsXCJDT01QTkQgXG5BVE9NIFxuRU5EXCIsZmxhZyw0LDQsMUlBTiw0LDEuMjMsPGNoYXJ0PjwvY2hhcnQ+LFwie1wiXCJzZXJpZXNcIlwiOlt7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdEZ1bmN0aW9uXCJcIjpcIlwic2lnbW9pZFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMC44NTk3MzkwOTc1NDMwMDA4LCAxLjA5NTc2MjU3MzI0ODE5NDYsIDUuMjYwNTM3MDY3OTg3OTU4LCAwLjA3OTc0MTg3OTk4MTc3NzM2XSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjowLjgxOTAxNTI2NDUxMTEwODR9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjowLjg0MjE2ODk4Njc5NzMzMjh9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjAuODc0MDkyMjIxMjYwMDcwOH0se1wiXCJ4XCJcIjoxLjYwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6MC44OTI0Mjc1MDQwNjI2NTI2fSx7XCJcInhcIlwiOjIuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC44MjQ5MDY3NjY0MTQ2NDIzfSx7XCJcInhcIlwiOjIuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC45MzI3NjY5MTQzNjc2NzU4fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC44NTIyOTc0MjUyNzAwODA2fSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC44MTc0NDkyNzE2Nzg5MjQ2fSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjgzOTQ2NDcyNDA2Mzg3MzN9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNzEzOTM4NzcyNjc4Mzc1Mn0se1wiXCJ4XCJcIjo1LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC41NTYxMTY3NTk3NzcwNjkxfSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjMyNzYyMjY4MTg1NjE1NTR9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTI0Nzk0NzQzOTU1MTM1MzV9LHtcIlwieFwiXCI6Ni41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTMwMDY3OTc0MzI4OTk0NzV9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMDU5NzAyMDc5NzQzMTQ2ODk2fV19LHtcIlwibmFtZVwiXCI6XCJcIlJ1bjoyMDIzLTA4LTA4XCJcIixcIlwiZml0TGluZUNvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInBvaW50Q29sb3JcIlwiOlwiXCIjZmZiYjc4XCJcIixcIlwic2hvd1BvaW50c1wiXCI6XCJcInBvaW50c1wiXCIsXCJcInBhcmFtZXRlcnNcIlwiOls1Ljc2MDkzMDIxOTU4MjU0NiwgMS42NTkxNzkzMjkzODMzMDEzLCA0LjY2NzE1NTkyOTcyMDg1MSwgMC43ODU4MTA5NTQ0MTIxNjUyXSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjo2LjE1Njk5MzM4OTEyOTYzOX0se1wiXCJ4XCJcIjowLjYwMDAwMDAyMzg0MTg1NzksXCJcInlcIlwiOjUuMjM2NzAxOTY1MzMyMDMxfSx7XCJcInhcIlwiOjEuMTAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjo2LjAxMDU2MDUxMjU0MjcyNX0se1wiXCJ4XCJcIjoxLjYwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6NS40OTU1MTI5NjIzNDEzMDl9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo2LjA4Nzc3MDQ2MjAzNjEzM30se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjUuNzk5ODY1NzIyNjU2MjV9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo1LjU5NzU0NjU3NzQ1MzYxM30se1wiXCJ4XCJcIjozLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjUuNTIwOTAyMTU2ODI5ODM0fSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjo1LjM2MDY1NDM1NDA5NTQ1OX0se1wiXCJ4XCJcIjo0LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6My41NTM5NzQ2Mjg0NDg0ODYzfSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjU3NzIzNjI5NDc0NjM5OX0se1wiXCJ4XCJcIjo1LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS4wMDAxMjY0ODEwNTYyMTM0fSx7XCJcInhcIlwiOjYuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjkzMDU3OTc4MTUzMjI4NzZ9LHtcIlwieFwiXCI6Ni41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNjAzMzYzODcxNTc0NDAxOX0se1wiXCJ4XCJcIjo3LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC40MjAzNjg1NTIyMDc5NDY4fV19XSxcIlwiY2hhcnRPcHRpb25zXCJcIjp7XCJcInhBeGlzTmFtZVwiXCI6XCJcIkNvbmMuXCJcIixcIlwieUF4aXNOYW1lXCJcIjpcIlwiQWN0aXZpdHlcIlwiLFwiXCJ0aXRsZVwiXCI6XCJcIkRvc2UtUmVzcG9uc2UgY3VydmVzXCJcIn19XCIsdGV4dCwsXG5Db2xvbWJpYSxNRFJUREVWU05IVEhES1BUTFRXRkVFSUZFRVlIU1BGSE4sRkMoRikoRiljMWNjYyhPQzJDQ05DQzIpY2MxLDE0ODAwMjksMzYuMzMwOTQ0MDYxMjc5Myw5OTUxNTIwNTAsMSBDT1VSVCBIT1VTRSBTUVVBUkUsaHR0cHM6Ly9kYXRhZ3Jvay5haS9pbWcvc2xpZGVzL2FjY2Vzcy1kYi1jb25uZWN0LnBuZyxpZCxFcnJvck1lc3NhZ2UsXCJDT01QTkQgXG5BVE9NIFxuRU5EXCIsZmxhZyw1LDUsNFVKMSw1LDEuMjMsPGNoYXJ0PjwvY2hhcnQ+LFwie1wiXCJzZXJpZXNcIlwiOlt7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdEZ1bmN0aW9uXCJcIjpcIlwic2lnbW9pZFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbNi40OTk1MDg4MzE0MTUzNjU1LCAyLjQyNzAzNTEwMDQ1Mzk5MTQsIDUuMTc4NjU5NTM1MzQ4NTc5LCAwLjYyNTY1MzM0NjI0MTU3N10sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6Ni40OTYyMzE1NTU5Mzg3MjF9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjo2LjQyNTQzMzYzNTcxMTY3fSx7XCJcInhcIlwiOjEuMTAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjo3LjA0MDA2Mzg1ODAzMjIyN30se1wiXCJ4XCJcIjoxLjYwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6Ni4xMTE1NDAzMTc1MzU0fSx7XCJcInhcIlwiOjIuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6Ni42ODA3Mjg0MzU1MTYzNTd9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo2LjQwNjc3NDUyMDg3NDAyM30se1wiXCJ4XCJcIjozLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjYuNjExMjY5NDc0MDI5NTQxfSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NS44ODkwOTQzNTI3MjIxNjh9LHtcIlwieFwiXCI6NC4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjYuNzUzNDQ3MDU1ODE2NjV9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjYuMzYxNDM1ODkwMTk3NzU0fSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjo0LjE2NjY5NzUwMjEzNjIzMDV9LHtcIlwieFwiXCI6NS41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuMTcyMTE4OTAyMjA2NDIxfSx7XCJcInhcIlwiOjYuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjgwMTA0ODk5NDA2NDMzMX0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC40NjQwMDIxMDI2MTM0NDkxfSx7XCJcInhcIlwiOjcuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjAwMTAzNTc2Njc5MjQ4MzYyNzh9XX0se1wiXCJuYW1lXCJcIjpcIlwiUnVuOjIwMjMtMDgtMDhcIlwiLFwiXCJmaXRMaW5lQ29sb3JcIlwiOlwiXCIjZmZiYjc4XCJcIixcIlwicG9pbnRDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJzaG93UG9pbnRzXCJcIjpcIlwicG9pbnRzXCJcIixcIlwicGFyYW1ldGVyc1wiXCI6WzEuNDczNDM4MTM0NzQ0NjQwMSwgMS4xNjQ5ODA1MTg4MDc0MTk2LCA0LjgyOTU4NjA4ODY2NDIxLCAwLjA5NTAwNTQ1NDk2NzEwMDA3XSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjoxLjUyNzkwOTYzNjQ5NzQ5NzZ9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjoxLjM1NTk5NzQ0MzE5OTE1Nzd9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjEuNTI0NjM3ODE4MzM2NDg2OH0se1wiXCJ4XCJcIjoxLjYwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6MS41NTY3NjU3OTQ3NTQwMjgzfSx7XCJcInhcIlwiOjIuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MS40MTE0MjQwNDA3OTQzNzI2fSx7XCJcInhcIlwiOjIuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MS40MDQ1MDEwODA1MTMwMDA1fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MS40NzY5ODI5NTExNjQyNDU2fSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MS40ODc1NTAwMjAyMTc4OTU1fSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjI5OTE5ODc0NjY4MTIxMzR9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuOTIyOTYxNDEzODYwMzIxfSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjY1MjAwNDQ4MDM2MTkzODV9LHtcIlwieFwiXCI6NS41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTUzNTA5NzgwNzY0NTc5Nzd9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTA3ODkwMzA3OTAzMjg5OH0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4xNzI3NjQ0OTUwMTUxNDQzNX0se1wiXCJ4XCJcIjo3LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4xNDA2NjYwODI1MDE0MTE0NH1dfV0sXCJcImNoYXJ0T3B0aW9uc1wiXCI6e1wiXCJ4QXhpc05hbWVcIlwiOlwiXCJDb25jLlwiXCIsXCJcInlBeGlzTmFtZVwiXCI6XCJcIkFjdGl2aXR5XCJcIixcIlwidGl0bGVcIlwiOlwiXCJEb3NlLVJlc3BvbnNlIGN1cnZlc1wiXCJ9fVwiLHRleHQsLFxuQ29zdGEgUmljYSxNS1NUS0VFSVFUSUtUTExLRFNSVEFLWUhLUkxRSVZMLENDKEMpQ2MxY2NjKGNjMSlDKEMpQyg9TylOMkNDQ0MyQyg9TylPQ0NDYzNjY2NjYzMsMTQ4MDAxOCwzNi4zMzA5NDQwNjEyNzkzLDk5NTA4NDIxOCw0MDQxIFNPVVRIV0VTVEVSTiBCTFZELGh0dHBzOi8vZGF0YWdyb2suYWkvaW1nL3NsaWRlcy9hY2Nlc3MtZGItY29ubmVjdC5wbmcsaWQsRXJyb3JNZXNzYWdlLFwiQ09NUE5EIFxuQVRPTSBcbkVORFwiLGZsYWcsNiw2LDJCUFcsNiwxLjIzLDxjaGFydD48L2NoYXJ0PixcIntcIlwic2VyaWVzXCJcIjpbe1wiXCJuYW1lXCJcIjpcIlwiUnVuOjIwMjMtMDgtMDhcIlwiLFwiXCJmaXRGdW5jdGlvblwiXCI6XCJcInNpZ21vaWRcIlwiLFwiXCJmaXRMaW5lQ29sb3JcIlwiOlwiXCIjMWY3N2I0XCJcIixcIlwicG9pbnRDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJzaG93UG9pbnRzXCJcIjpcIlwicG9pbnRzXCJcIixcIlwicGFyYW1ldGVyc1wiXCI6WzIuNDgzMzY0MTg0MzMxMTIyNywgLTEuODk0NTk3ODc0MjA5MDA2MiwgNC42NzExMjc3MDgwOTI1NjgsIDAuMjQxNTk4NjEzMTE4MTUxNTNdLFwiXCJwb2ludHNcIlwiOlt7XCJcInhcIlwiOjAuMTAwMDAwMDAxNDkwMTE2MTIsXCJcInlcIlwiOjAuMDk2OTUyNDE2MDAyNzUwNH0se1wiXCJ4XCJcIjowLjYwMDAwMDAyMzg0MTg1NzksXCJcInlcIlwiOjAuMDI4NDgzMDQwNjMwODE3NDEzfSx7XCJcInhcIlwiOjEuMTAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjowLjIyMDg3MTc2MTQ0MTIzMDc3fSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjowLjAwNjg5MTU1NDY4NzE3MjE3NDV9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjQzMDU4Nzk3NzE3MDk0NDJ9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjQ0Nzc0MTE1MDg1NjAxODA3fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MC40NTM0NjMxOTY3NTQ0NTU1N30se1wiXCJ4XCJcIjozLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjAuMjM3MDU5MzEwMDc4NjIwOX0se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC40NjU3OTUzOTc3NTg0ODM5fSx7XCJcInhcIlwiOjQuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjE1NTIwMDcxOTgzMzM3NH0se1wiXCJ4XCJcIjo1LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Mi4yMjk0MDcwNzIwNjcyNjA3fSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjQzMTE1MzA1OTAwNTczNzN9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuMzM4NDYxMTYwNjU5Nzl9LHtcIlwieFwiXCI6Ni41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuNjA4MjAxMDI2OTE2NTA0fSx7XCJcInhcIlwiOjcuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjgxMzYxNDM2ODQzODcyMDd9XX0se1wiXCJuYW1lXCJcIjpcIlwiUnVuOjIwMjMtMDgtMDhcIlwiLFwiXCJmaXRMaW5lQ29sb3JcIlwiOlwiXCIjZmZiYjc4XCJcIixcIlwicG9pbnRDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJzaG93UG9pbnRzXCJcIjpcIlwicG9pbnRzXCJcIixcIlwicGFyYW1ldGVyc1wiXCI6WzUuMjI0NTczNTIxNjQyMDMzLCAxLjQ0NTQwMzM5MjQxOTg1MjgsIDUuNjAxNDE5Nzc0NjA3NjUzNSwgMC4yODIzMjE2MDU0MTk3NTc3XSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjo0Ljk1MDI3NDk0NDMwNTQyfSx7XCJcInhcIlwiOjAuNjAwMDAwMDIzODQxODU3OSxcIlwieVwiXCI6NS4xNzU0Njc5Njc5ODcwNjA1fSx7XCJcInhcIlwiOjEuMTAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjo1LjI3Njc1Mjk0ODc2MDk4Nn0se1wiXCJ4XCJcIjoxLjYwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6NS41ODkyOTQ5MTA0MzA5MDh9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo1LjYxNjk5NDg1Nzc4ODA4Nn0se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjUuMTIwODEzODQ2NTg4MTM1fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NS4zNDA3NjY5MDY3MzgyODF9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo0Ljg3NjQ3MTA0MjYzMzA1N30se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6NC45NDk5OTM2MTAzODIwOH0se1wiXCJ4XCJcIjo0LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6NS4xNjI1NjQ3NTQ0ODYwODR9LHtcIlwieFwiXCI6NS4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjQuMzk5NTU3NTkwNDg0NjE5fSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjc5Nzc5Njk2NDY0NTM4NTd9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuMDIyOTg3MjQ2NTEzMzY2N30se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC40ODI3NTYwMTg2Mzg2MTA4NH0se1wiXCJ4XCJcIjo3LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4xMDQwODkzMTk3MDU5NjMxM31dfV0sXCJcImNoYXJ0T3B0aW9uc1wiXCI6e1wiXCJ4QXhpc05hbWVcIlwiOlwiXCJDb25jLlwiXCIsXCJcInlBeGlzTmFtZVwiXCI6XCJcIkFjdGl2aXR5XCJcIixcIlwidGl0bGVcIlwiOlwiXCJEb3NlLVJlc3BvbnNlIGN1cnZlc1wiXCJ9fVwiLHRleHQsLFxuQ3ViYSxNSEFJTFJZRklSUkxGWUhJRllLSVlTTElTS0tIUVNMUFNEVlJRRixDT2MxY2NjMmMoYzEpYyhDQyg9TylOM0NDQ0MzQyg9TylPYzRjY2MoQyljYzRPQyljKEMpbjJDKD1PKWM1Y2NjKENsKWNjNSwxNDgwMDE5LDM2LjMzMTE1NzY4NDMyNjE3LDk5NTA4MTkyOCwxMjI3IFVTIEhJR0hXQVkgMTEsaHR0cHM6Ly9kYXRhZ3Jvay5haS9pbWcvc2xpZGVzL2FjY2Vzcy1kYi1jb25uZWN0LnBuZyxpZCxFcnJvck1lc3NhZ2UsXCJDT01QTkQgXG5BVE9NIFxuRU5EXCIsZmxhZyw3LDcsMVFCUyw3LDEuMjMsPGNoYXJ0PjwvY2hhcnQ+LFwie1wiXCJzZXJpZXNcIlwiOlt7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdEZ1bmN0aW9uXCJcIjpcIlwic2lnbW9pZFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMy4zMjA4Mzg2Nzk3MTM5MjUsIC0xLjI0MjE2MTk5ODczMTY3MjgsIDQuODMxMzI1NDI1MjI1MjU2LCAwLjMyMzYwMTEwOTg0MDMwNzJdLFwiXCJwb2ludHNcIlwiOlt7XCJcInhcIlwiOjAuMTAwMDAwMDAxNDkwMTE2MTIsXCJcInlcIlwiOjAuMzcyNzQ3MDMzODM0NDU3NH0se1wiXCJ4XCJcIjowLjYwMDAwMDAyMzg0MTg1NzksXCJcInlcIlwiOjAuMTIzNjUwMTQxMDYwMzUyMzN9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjAuNDg0MjI0Njc3MDg1ODc2NDZ9LHtcIlwieFwiXCI6MS42MDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjAuMjI2NDQ2NTA5MzYxMjY3MX0se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjAuMTY4MjE3OTQyMTE4NjQ0NzF9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjM4NzkwMTQ1NTE2Mzk1NTd9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjU0NzAyNDQ4ODQ0OTA5Njd9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjowLjM0MTkwNTM1NTQ1MzQ5MTJ9LHtcIlwieFwiXCI6NC4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNzY1NTEyMDQ5MTk4MTUwNn0se1wiXCJ4XCJcIjo0LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS4yMzQ2NTE2ODQ3NjEwNDc0fSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjQ1MzMzNjcxNTY5ODI0Mn0se1wiXCJ4XCJcIjo1LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Mi45NTY1NDkxNjc2MzMwNTY2fSx7XCJcInhcIlwiOjYuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjMzNTI5OTQ5MTg4MjMyNH0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6My4yNDAyOTA4ODAyMDMyNDd9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjMuMTEwNzIxODI2NTUzMzQ0N31dfSx7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMy42NDAxODUzNTIxNTExMDk0LCAxLjI2MjExNTg4ODc1MDEzLCA1LjM5OTAyODA3NDQwMjc0NCwgMC41MDg5NTgwODMwMDY4MDkxXSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjozLjg1ODU1OTg0Njg3ODA1MTh9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjozLjYwNzcyMDYxMzQ3OTYxNDN9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjMuODU1MjUyMjY1OTMwMTc2fSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjozLjYxOTAzOTI5NzEwMzg4Mn0se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjMuODM5Mzg4MzcwNTEzOTE2fSx7XCJcInhcIlwiOjIuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6My4zMzUyODMwNDEwMDAzNjZ9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjozLjU3MTE0MTQ4MTM5OTUzNn0se1wiXCJ4XCJcIjozLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjMuNDE1NTA0NjkzOTg0OTg1NH0se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6My43MzE2NjQ2NTc1OTI3NzM0fSx7XCJcInhcIlwiOjQuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjA2ODAxNTU3NTQwODkzNTV9LHtcIlwieFwiXCI6NS4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuODkxMDY2NTUxMjA4NDk2fSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjYwMjI3NTM3MTU1MTUxMzd9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNzY1MjU3NjU2NTc0MjQ5M30se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC42ODc1MzI2MDM3NDA2OTIxfSx7XCJcInhcIlwiOjcuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjU4Mjg4NzE3MjY5ODk3NDZ9XX1dLFwiXCJjaGFydE9wdGlvbnNcIlwiOntcIlwieEF4aXNOYW1lXCJcIjpcIlwiQ29uYy5cIlwiLFwiXCJ5QXhpc05hbWVcIlwiOlwiXCJBY3Rpdml0eVwiXCIsXCJcInRpdGxlXCJcIjpcIlwiRG9zZS1SZXNwb25zZSBjdXJ2ZXNcIlwifX1cIix0ZXh0LCxcbkl0YWx5LE1TTkZITkVIVk1RRllSTk5MS1RLR1ZGR1JRLENDKEMpQ2MxY2NjKGNjMSlDKEMpQyg9TylOMkNDQ0MyQyg9TylPQ0NPW04rXSg9TylbTy1dLDE0ODAwMjAsMzYuMzMxMTU3Njg0MzI2MTcsOTk1MDIsXCIxNjgtNDYgOTFTVCBBVkUuLCAyTkQgRkxSXCIsaHR0cHM6Ly9kYXRhZ3Jvay5haS9pbWcvc2xpZGVzL2FjY2Vzcy1kYi1jb25uZWN0LnBuZyxpZCxFcnJvck1lc3NhZ2UsXCJDT01QTkQgXG5BVE9NIFxuRU5EXCIsZmxhZyw4LDgsMVpQOCw4LDEuMjMsPGNoYXJ0PjwvY2hhcnQ+LFwie1wiXCJzZXJpZXNcIlwiOlt7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdEZ1bmN0aW9uXCJcIjpcIlwic2lnbW9pZFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMi4yOTM1OTIxMDU5MjM4MDksIDEuMzc4MTU4NjU0OTE0MTgzNSwgNS4xMDI1ODk4MDM4Njc2NjA1LCAwLjAzNDkzODUxMjQ1MjkxMjkxXSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjoyLjEyODcyODM4OTczOTk5MDJ9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjoyLjI2Nzk3MjIzMDkxMTI1NX0se1wiXCJ4XCJcIjoxLjEwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6Mi4zOTg0NDI1MDY3OTAxNjF9LHtcIlwieFwiXCI6MS42MDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjIuNTEzMDYyMjM4NjkzMjM3M30se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjIuMzI1NTExNjkzOTU0NDY3OH0se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjIuMTI3MzQwNzkzNjA5NjE5fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6Mi40NzI1OTc4Mzc0NDgxMn0se1wiXCJ4XCJcIjozLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjIuMTMxMTgxNDc4NTAwMzY2fSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoyLjA5MDQyMTQzODIxNzE2M30se1wiXCJ4XCJcIjo0LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Mi4wMjI5OTE2NTcyNTcwOH0se1wiXCJ4XCJcIjo1LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS4xMTA1MDU5Mzg1Mjk5NjgzfSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjQ0OTQ0ODU4NTUxMDI1Mzl9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTM3NTYzNTg2MjM1MDQ2NH0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4wMzYzNTExMjE5NjIwNzA0NjV9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTYxOTc3MTEyMjkzMjQzNH1dfSx7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbNS45NTMxMjU0OTk0Mzk4NzksIDEuMjUyODYyMDI1NTMwNjUyOCwgNS4xODc2Mzc0NDAxNDk4MDIsIDAuMzExMDM0ODc1MzI2MDg4Nl0sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6NS42NTg1MjgzMjc5NDE4OTQ1fSx7XCJcInhcIlwiOjAuNjAwMDAwMDIzODQxODU3OSxcIlwieVwiXCI6NS45MTExNTIzNjI4MjM0ODZ9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjUuOTI0OTIwMDgyMDkyMjg1fSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjo1Ljg0Njk0Mzg1NTI4NTY0NDV9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo1LjkyOTQ3MjkyMzI3ODgwOX0se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjYuMTkwMDM3NzI3MzU1OTU3fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6Ni4yMzYxNzk4Mjg2NDM3OTl9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo2LjE0MTAxOTM0NDMyOTgzNH0se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6NS4yOTUyMTA4MzgzMTc4NzF9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjUuMjY1ODAxOTA2NTg1NjkzfSx7XCJcInhcIlwiOjUuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjM3MjI4NTEyNzYzOTc3MDV9LHtcIlwieFwiXCI6NS41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuODI5OTIyNjc2MDg2NDI1OH0se1wiXCJ4XCJcIjo2LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4zMjY5MDkwMDU2NDE5MzcyNn0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC42Mjc0NTQzNDA0NTc5MTYzfSx7XCJcInhcIlwiOjcuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjg0NDE4NTcwOTk1MzMwODF9XX1dLFwiXCJjaGFydE9wdGlvbnNcIlwiOntcIlwieEF4aXNOYW1lXCJcIjpcIlwiQ29uYy5cIlwiLFwiXCJ5QXhpc05hbWVcIlwiOlwiXCJBY3Rpdml0eVwiXCIsXCJcInRpdGxlXCJcIjpcIlwiRG9zZS1SZXNwb25zZSBjdXJ2ZXNcIlwifX1cIix0ZXh0LCxcblJ3YW5kYSxNUE5TRVBBU0xMRUxGTlNJQVRRR0VMVlJTTEtBR05BU0ssQ0MoQylDYzFjY2MoY2MxKUMoQylDKD1PKU4yQ0NDQzJDKD1PKU9DQ08sMTQ4MDAyMSwzNi4zMzEzNzEzMDczNzMwNSw5OTUwMzcyNDcsXCIxNjgtNDYgOTFTVCBBVkUuLCAyTkQgRkxSXCIsaHR0cHM6Ly9kYXRhZ3Jvay5haS9pbWcvc2xpZGVzL2FjY2Vzcy1kYi1jb25uZWN0LnBuZyxpZCxFcnJvck1lc3NhZ2UsXCJDT01QTkQgXG5BVE9NIFxuRU5EXCIsZmxhZyw5LDksMkJESiw5LDEuMjMsPGNoYXJ0PjwvY2hhcnQ+LFwie1wiXCJzZXJpZXNcIlwiOlt7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdEZ1bmN0aW9uXCJcIjpcIlwic2lnbW9pZFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiIzFmNzdiNFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMy44MjA5OTcyMjAyNjU0NDc0LCAxLjM3NzkyMTY3MTY0NDg1MDYsIDUuMjk5ODgyMjI4NDM5Njg2LCAwLjA2MDQwNjQ1NTE5MDY5NjA4XSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjozLjc4MjExMDkyOTQ4OTEzNTd9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjozLjU0MjQzMzAyMzQ1Mjc1OX0se1wiXCJ4XCJcIjoxLjEwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6My43MDA4Njc0MTQ0NzQ0ODczfSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjozLjcxNzMwMTYwNzEzMTk1OH0se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjQuMDI0NDUyMjA5NDcyNjU2fSx7XCJcInhcIlwiOjIuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NC4wMTM4OTkzMjYzMjQ0NjN9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjozLjk0NTA5NDM0NzAwMDEyMn0se1wiXCJ4XCJcIjozLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjMuODY2NjIxOTcxMTMwMzcxfSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjc0NjE2MjY1Mjk2OTM2MDR9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjMuMzQ1NDc0MDA0NzQ1NDgzNH0se1wiXCJ4XCJcIjo1LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6Mi42MTk0NDMxNzgxNzY4OH0se1wiXCJ4XCJcIjo1LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC45OTk0MDUwMjY0MzU4NTJ9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNDYyNTk3OTM2MzkxODMwNDR9LHtcIlwieFwiXCI6Ni41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMDU0MTM0NjExMDQwMzUzNzc1fSx7XCJcInhcIlwiOjcuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjA1NzExMTg3NDIyMjc1NTQzfV19LHtcIlwibmFtZVwiXCI6XCJcIlJ1bjoyMDIzLTA4LTA4XCJcIixcIlwiZml0TGluZUNvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInBvaW50Q29sb3JcIlwiOlwiXCIjZmZiYjc4XCJcIixcIlwic2hvd1BvaW50c1wiXCI6XCJcInBvaW50c1wiXCIsXCJcInBhcmFtZXRlcnNcIlwiOls1LjYzMTgwNzk2NTc3MjYwMzUsIDEuODQ5NTQ5Mzc3MDAwMDU5NSwgNS4zOTE3OTMzMTI0NzExMTYsIDAuMTcwNjA3MDc1ODczNDg0NDJdLFwiXCJwb2ludHNcIlwiOlt7XCJcInhcIlwiOjAuMTAwMDAwMDAxNDkwMTE2MTIsXCJcInlcIlwiOjUuNDU4MDc5ODE0OTEwODg5fSx7XCJcInhcIlwiOjAuNjAwMDAwMDIzODQxODU3OSxcIlwieVwiXCI6NS41NTQ0MjcxNDY5MTE2MjF9LHtcIlwieFwiXCI6MS4xMDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjUuNzk5OTgzMDI0NTk3MTY4fSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjo1LjM2NDE0MDAzMzcyMTkyNH0se1wiXCJ4XCJcIjoyLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjUuODY0NDg1NzQwNjYxNjIxfSx7XCJcInhcIlwiOjIuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NS40NTA5ODA2NjMyOTk1NjA1fSx7XCJcInhcIlwiOjMuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6NS43MDI1NzQ3Mjk5MTk0MzR9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjo1LjczMTQ1MzQxODczMTY4OTV9LHtcIlwieFwiXCI6NC4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjUuNTEyMzQ0MzYwMzUxNTYyNX0se1wiXCJ4XCJcIjo0LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6NS43MjQzOTU3NTE5NTMxMjV9LHtcIlwieFwiXCI6NS4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjQuMzU0NTA2OTY5NDUxOTA0fSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjczMDc2NjY1NDAxNDU4NzR9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNjMwNTkzNjU3NDkzNTkxM30se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4wMzUxODM0MzcxNjg1OTgxNzV9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNzU3NTE2OTIwNTY2NTU4OH1dfV0sXCJcImNoYXJ0T3B0aW9uc1wiXCI6e1wiXCJ4QXhpc05hbWVcIlwiOlwiXCJDb25jLlwiXCIsXCJcInlBeGlzTmFtZVwiXCI6XCJcIkFjdGl2aXR5XCJcIixcIlwidGl0bGVcIlwiOlwiXCJEb3NlLVJlc3BvbnNlIGN1cnZlc1wiXCJ9fVwiLHRleHQsLFxuU3dpdHplcmxhbmQsSVJWVkdSWUxJRVZXS0FBR01ETURLVkxGTFdTU0RFSSxDTjFDQ0MoQ0MxKU9jMmNjYyhjYzIpQyhGKShGKUYsMTQ4MDAyOCwzNi4zMzEzNzEzMDczNzMwNSw5OTUwNCw5Mi0xMSAxNzlUSCBQTEFDRSxodHRwczovL2RhdGFncm9rLmFpL2ltZy9zbGlkZXMvYWNjZXNzLWRiLWNvbm5lY3QucG5nLGlkLEVycm9yTWVzc2FnZSxcIkNPTVBORCBcbkFUT00gXG5FTkRcIixmbGFnLDksMTAsMUlBTiwxMCwxLjIzLDxjaGFydD48L2NoYXJ0PixcIntcIlwic2VyaWVzXCJcIjpbe1wiXCJuYW1lXCJcIjpcIlwiUnVuOjIwMjMtMDgtMDhcIlwiLFwiXCJmaXRGdW5jdGlvblwiXCI6XCJcInNpZ21vaWRcIlwiLFwiXCJmaXRMaW5lQ29sb3JcIlwiOlwiXCIjMWY3N2I0XCJcIixcIlwicG9pbnRDb2xvclwiXCI6XCJcIiMxZjc3YjRcIlwiLFwiXCJzaG93UG9pbnRzXCJcIjpcIlwicG9pbnRzXCJcIixcIlwicGFyYW1ldGVyc1wiXCI6WzEuMTE5MDI1NTg2NTA5NzQ3MSwgMi4zMTYzODk1MTYxNTQ0NDM3LCA1LjQ5Njg4NjYxODIyNzkxOTUsIDAuMjAzNTIwNDA0NzI4OTA1Ml0sXCJcInBvaW50c1wiXCI6W3tcIlwieFwiXCI6MC4xMDAwMDAwMDE0OTAxMTYxMixcIlwieVwiXCI6MS4xMDU3NjgzMjI5NDQ2NDExfSx7XCJcInhcIlwiOjAuNjAwMDAwMDIzODQxODU3OSxcIlwieVwiXCI6MS4xMDE5Njk3MTg5MzMxMDU1fSx7XCJcInhcIlwiOjEuMTAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjoxLjA4MTg2MDc4MDcxNTk0MjR9LHtcIlwieFwiXCI6MS42MDAwMDAwMjM4NDE4NTgsXCJcInlcIlwiOjEuMDYyOTk3ODE3OTkzMTY0fSx7XCJcInhcIlwiOjIuMDk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6MS4wNDY0NDc1MTU0ODc2NzF9LHtcIlwieFwiXCI6Mi41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoxLjEyMTcyNDk2MzE4ODE3MTR9LHtcIlwieFwiXCI6My4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoxLjIxNjY5OTYwMDIxOTcyNjZ9LHtcIlwieFwiXCI6My41OTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjoxLjIxNTQ3NzcwNTAwMTgzMX0se1wiXCJ4XCJcIjo0LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS4wNTgxODkzOTIwODk4NDM4fSx7XCJcInhcIlwiOjQuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjoxLjE3NDc5OTU2MTUwMDU0OTN9LHtcIlwieFwiXCI6NS4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjEuMDE4MTEyNzc4NjYzNjM1M30se1wiXCJ4XCJcIjo1LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC41MzQ0NTIzMTkxNDUyMDI2fSx7XCJcInhcIlwiOjYuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjI1Njk1MjY0MzM5NDQ3MDJ9LHtcIlwieFwiXCI6Ni41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMTkxMjIwNzMwNTQzMTM2Nn0se1wiXCJ4XCJcIjo3LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4xNTA2MDUzODA1MzUxMjU3M31dfSx7XCJcIm5hbWVcIlwiOlwiXCJSdW46MjAyMy0wOC0wOFwiXCIsXCJcImZpdExpbmVDb2xvclwiXCI6XCJcIiNmZmJiNzhcIlwiLFwiXCJwb2ludENvbG9yXCJcIjpcIlwiI2ZmYmI3OFwiXCIsXCJcInNob3dQb2ludHNcIlwiOlwiXCJwb2ludHNcIlwiLFwiXCJwYXJhbWV0ZXJzXCJcIjpbMy4xMDM4NTgxMDI1ODA1Nzg1LCAyLjAwMzIyMjQyMDQxODUyNDUsIDUuMDg3NjAyODI1OTg5MTYzLCAwLjEzMjc3OTg4NTEyNDkyNzUzXSxcIlwicG9pbnRzXCJcIjpbe1wiXCJ4XCJcIjowLjEwMDAwMDAwMTQ5MDExNjEyLFwiXCJ5XCJcIjozLjA0OTg1MDk0MDcwNDM0NTd9LHtcIlwieFwiXCI6MC42MDAwMDAwMjM4NDE4NTc5LFwiXCJ5XCJcIjoyLjgwNTIxNzc0MjkxOTkyMn0se1wiXCJ4XCJcIjoxLjEwMDAwMDAyMzg0MTg1OCxcIlwieVwiXCI6My4zNDE1MjUzMTYyMzg0MDMzfSx7XCJcInhcIlwiOjEuNjAwMDAwMDIzODQxODU4LFwiXCJ5XCJcIjozLjA1NDk4NDMzMTEzMDk4MTR9LHtcIlwieFwiXCI6Mi4wOTk5OTk5MDQ2MzI1Njg0LFwiXCJ5XCJcIjozLjI1MDA3NDg2MzQzMzgzOH0se1wiXCJ4XCJcIjoyLjU5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjMuMDQzMjU4NjY2OTkyMTg3NX0se1wiXCJ4XCJcIjozLjA5OTk5OTkwNDYzMjU2ODQsXCJcInlcIlwiOjMuMjY1ODUyNDUxMzI0NDYzfSx7XCJcInhcIlwiOjMuNTk5OTk5OTA0NjMyNTY4NCxcIlwieVwiXCI6Mi45NDc1NzI0Njk3MTEzMDM3fSx7XCJcInhcIlwiOjQuMDk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjozLjE5Mjk4OTgyNjIwMjM5MjZ9LHtcIlwieFwiXCI6NC41OTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjIuNzQ2MDA2MDExOTYyODkwNn0se1wiXCJ4XCJcIjo1LjA5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MS42MTc1ODYxMzU4NjQyNTc4fSx7XCJcInhcIlwiOjUuNTk5OTk5OTA0NjMyNTY4LFwiXCJ5XCJcIjowLjMwMDY2MDg0ODYxNzU1Mzd9LHtcIlwieFwiXCI6Ni4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuMzQ0NDgwMzA1OTEwMTEwNX0se1wiXCJ4XCJcIjo2LjU5OTk5OTkwNDYzMjU2OCxcIlwieVwiXCI6MC4wMTU1Mzc5NzE2MzA2OTI0ODJ9LHtcIlwieFwiXCI6Ny4wOTk5OTk5MDQ2MzI1NjgsXCJcInlcIlwiOjAuNTUyNzM1ODA1NTExNDc0Nn1dfV0sXCJcImNoYXJ0T3B0aW9uc1wiXCI6e1wiXCJ4QXhpc05hbWVcIlwiOlwiXCJDb25jLlwiXCIsXCJcInlBeGlzTmFtZVwiXCI6XCJcIkFjdGl2aXR5XCJcIixcIlwidGl0bGVcIlwiOlwiXCJEb3NlLVJlc3BvbnNlIGN1cnZlc1wiXCJ9fVwiLHRleHQsLFxuLCwsLCwsLCwsLCwsLCwsLCwsLCwsYCk7XG50ZXN0RGF0YS5jb2x1bW5zLmFkZChERy5Db2x1bW4uZnJvbUxpc3QoREcuVFlQRS5CWVRFX0FSUkFZLCAnQmluYXJ5SW1hZ2UnLCBBcnJheS5mcm9tKG5ldyBVaW50OEFycmF5KDExKSkpKTtcbiJdfQ==","var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nimport { testData } from './dataframe-utils';\nimport { changeOptionsSaveLayout, filterAsync, loadLayout, selectFilterChangeCurrent, testViewerInternal } from './test-viewer-utils';\nconst STANDART_TIMEOUT = 30000;\nconst BENCHMARK_TIMEOUT = 10800000;\nconst stdLog = console.log.bind(console);\nconst stdInfo = console.info.bind(console);\nconst stdWarn = console.warn.bind(console);\nconst stdError = console.error.bind(console);\nexport const tests = {};\nconst autoTestsCatName = 'Auto Tests';\nconst demoCatName = 'Demo';\nconst detectorsCatName = 'Detectors';\nconst coreCatName = 'Core';\nconst wasRegistered = {};\nexport let currentCategory;\nexport var assure;\n(function (assure) {\n function notNull(value, name) {\n if (value == null)\n throw new Error(`${name == null ? 'Value' : name} not defined`);\n }\n assure.notNull = notNull;\n})(assure || (assure = {}));\nexport class TestContext {\n constructor(catchUnhandled, report, returnOnFail) {\n this.catchUnhandled = true;\n this.report = false;\n this.returnOnFail = false;\n if (catchUnhandled !== undefined)\n this.catchUnhandled = catchUnhandled;\n if (report !== undefined)\n this.report = report;\n if (returnOnFail !== undefined)\n this.returnOnFail = returnOnFail;\n }\n ;\n}\nexport class Test {\n constructor(category, name, test, options) {\n var _a;\n this.category = category;\n this.name = name;\n options !== null && options !== void 0 ? options : (options = {});\n (_a = options.timeout) !== null && _a !== void 0 ? _a : (options.timeout = STANDART_TIMEOUT);\n this.options = options;\n this.test = () => __awaiter(this, void 0, void 0, function* () {\n return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {\n var _b;\n let result = '';\n try {\n if (DG.Test.isInDebug)\n debugger;\n let res = yield test();\n try {\n result = (_b = res === null || res === void 0 ? void 0 : res.toString()) !== null && _b !== void 0 ? _b : '';\n }\n catch (e) {\n result = 'Can\\'t convert test\\'s result to string';\n console.error(`Can\\'t convert test\\'s result to string in the ${this.category}:${this.name} test`);\n }\n }\n catch (e) {\n reject(e);\n }\n resolve(result);\n }));\n });\n }\n}\nexport class Category {\n}\nexport class NodeTestExecutionOptions {\n}\nexport class TestExecutionOptions {\n}\nexport function testEvent(event, handler, trigger, ms = 0, reason = `timeout`) {\n return __awaiter(this, void 0, void 0, function* () {\n return new Promise((resolve, reject) => {\n const sub = event.subscribe((args) => {\n try {\n handler(args);\n resolve('OK');\n }\n catch (e) {\n reject(e);\n }\n finally {\n sub.unsubscribe();\n clearTimeout(timeout);\n }\n });\n const timeout = setTimeout(() => {\n sub.unsubscribe();\n // eslint-disable-next-line prefer-promise-reject-errors\n reject(reason);\n }, ms);\n trigger();\n });\n });\n}\nexport function testEventAsync(event, handler, trigger, ms = 0, reason = `timeout`) {\n return __awaiter(this, void 0, void 0, function* () {\n return new Promise((resolve, reject) => {\n const sub = event.subscribe((args) => {\n handler(args).then(() => {\n resolve('OK');\n }).catch((e) => {\n reject(e);\n }).finally(() => {\n sub.unsubscribe();\n clearTimeout(timeout);\n });\n });\n const timeout = setTimeout(() => {\n sub.unsubscribe();\n // eslint-disable-next-line prefer-promise-reject-errors\n reject(reason);\n }, ms);\n trigger();\n });\n });\n}\nexport function test(name, test, options) {\n if (tests[currentCategory] == undefined)\n tests[currentCategory] = {};\n if (tests[currentCategory].tests == undefined)\n tests[currentCategory].tests = [];\n tests[currentCategory].tests.push(new Test(currentCategory, name, test, options));\n}\n/* Tests two objects for equality, throws an exception if they are not equal. */\nexport function expect(actual, expected = true, error) {\n if (error)\n error = `${error}, `;\n else\n error = '';\n if (actual !== expected)\n throw new Error(`${error}Expected \"${expected}\", got \"${actual}\"`);\n}\nexport function expectFloat(actual, expected, tolerance = 0.001, error) {\n if ((actual === Number.POSITIVE_INFINITY && expected === Number.POSITIVE_INFINITY) ||\n (actual === Number.NEGATIVE_INFINITY && expected === Number.NEGATIVE_INFINITY) ||\n (actual === Number.NaN && expected === Number.NaN) || (isNaN(actual) && isNaN(expected)))\n return;\n const areEqual = Math.abs(actual - expected) < tolerance;\n expect(areEqual, true, `${error !== null && error !== void 0 ? error : ''} (tolerance = ${tolerance}; a = ${actual}, e = ${expected})`);\n if (!areEqual)\n throw new Error(`Expected ${expected}, got ${actual} (tolerance = ${tolerance})`);\n}\nexport function expectTable(actual, expected, error) {\n const expectedRowCount = expected.rowCount;\n const actualRowCount = actual.rowCount;\n expect(actualRowCount, expectedRowCount, `${error !== null && error !== void 0 ? error : ''}, row count`);\n for (const column of expected.columns) {\n const actualColumn = actual.columns.byName(column.name);\n if (actualColumn == null)\n throw new Error(`Column ${column.name} not found`);\n if (actualColumn.type != column.type)\n throw new Error(`Column ${column.name} type expected ${column.type} got ${actualColumn.type}`);\n for (let i = 0; i < expectedRowCount; i++) {\n const value = column.get(i);\n const actualValue = actualColumn.get(i);\n if (column.type == DG.TYPE.FLOAT)\n expectFloat(actualValue, value, 0.0001, error);\n else if (column.type == DG.TYPE.DATE_TIME)\n expect(actualValue.isSame(value), true, error);\n else\n expect(actualValue, value, error);\n }\n }\n}\nexport function expectObject(actual, expected) {\n for (const [expectedKey, expectedValue] of Object.entries(expected)) {\n if (!actual.hasOwnProperty(expectedKey))\n throw new Error(`Expected property \"${expectedKey}\" not found`);\n const actualValue = actual[expectedKey];\n if (actualValue instanceof Array && expectedValue instanceof Array)\n expectArray(actualValue, expectedValue);\n else if (actualValue instanceof Object && expectedValue instanceof Object)\n expectObject(actualValue, expectedValue);\n else if (Number.isFinite(actualValue) && Number.isFinite(expectedValue))\n expectFloat(actualValue, expectedValue);\n else if (actualValue != expectedValue)\n throw new Error(`Expected (${expectedValue}) for key '${expectedKey}', got (${actualValue})`);\n }\n}\nexport function expectArray(actual, expected) {\n const actualLength = actual.length;\n const expectedLength = expected.length;\n if (actualLength != expectedLength) {\n throw new Error(`Arrays are of different length: actual array length is ${actualLength} ` +\n `and expected array length is ${expectedLength}`);\n }\n for (let i = 0; i < actualLength; i++) {\n if (actual[i] instanceof Array && expected[i] instanceof Array)\n expectArray(actual[i], expected[i]);\n else if (actual[i] instanceof Object && expected[i] instanceof Object)\n expectObject(actual[i], expected[i]);\n else if (actual[i] != expected[i])\n throw new Error(`Expected ${expected[i]} at position ${i}, got ${actual[i]}`);\n }\n}\n/* Defines a test suite. */\nexport function category(category, tests_, options) {\n var _a;\n currentCategory = category;\n tests_();\n if (tests[currentCategory]) {\n tests[currentCategory].clear = (_a = options === null || options === void 0 ? void 0 : options.clear) !== null && _a !== void 0 ? _a : true;\n tests[currentCategory].timeout = options === null || options === void 0 ? void 0 : options.timeout;\n tests[currentCategory].benchmarks = options === null || options === void 0 ? void 0 : options.benchmarks;\n tests[currentCategory].stressTests = options === null || options === void 0 ? void 0 : options.stressTests;\n tests[currentCategory].owner = options === null || options === void 0 ? void 0 : options.owner;\n }\n}\n/* Defines a function to be executed before the tests in this category are executed. */\nexport function before(before) {\n if (tests[currentCategory] == undefined)\n tests[currentCategory] = {};\n tests[currentCategory].before = before;\n}\n/* Defines a function to be executed after the tests in this category are executed. */\nexport function after(after) {\n if (tests[currentCategory] == undefined)\n tests[currentCategory] = {};\n tests[currentCategory].after = after;\n}\nfunction addNamespace(s, f) {\n return s.replace(new RegExp(f.name, 'gi'), f.nqName);\n}\nexport function initAutoTests(package_, module) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;\n return __awaiter(this, void 0, void 0, function* () {\n const packageId = package_.id;\n if (wasRegistered[packageId])\n return;\n const moduleTests = module ? module.tests : tests;\n if (package_.name === 'DevTools' || (!!module && module._package.name === 'DevTools')) {\n for (const f of window.dartTests) {\n const arr = f.name.split(/\\s*\\|\\s*!/g);\n let name = (_a = arr.pop()) !== null && _a !== void 0 ? _a : f.name;\n let cat = arr.length ? coreCatName + ': ' + arr.join(': ') : coreCatName;\n let fullName = name.split(' | ');\n name = fullName[fullName.length - 1];\n fullName.unshift(cat);\n fullName.pop();\n cat = fullName.join(': ');\n if (moduleTests[cat] === undefined)\n moduleTests[cat] = { tests: [], clear: true };\n moduleTests[cat].tests.push(new Test(cat, name, f.test, { isAggregated: false, timeout: (_c = (_b = f.options) === null || _b === void 0 ? void 0 : _b.timeout) !== null && _c !== void 0 ? _c : STANDART_TIMEOUT, skipReason: (_d = f.options) === null || _d === void 0 ? void 0 : _d.skipReason, owner: (_e = f.options) === null || _e === void 0 ? void 0 : _e.owner, benchmark: (_g = (_f = f.options) === null || _f === void 0 ? void 0 : _f.benchmark) !== null && _g !== void 0 ? _g : false }));\n }\n }\n const moduleAutoTests = [];\n const moduleDemo = [];\n const moduleDetectors = [];\n const packFunctions = yield grok.dapi.functions.filter(`package.id = \"${packageId}\"`).list();\n const reg = new RegExp(/skip:\\s*([^,\\s]+)|wait:\\s*(\\d+)|cat:\\s*([^,\\s]+)|timeout:\\s*(\\d+)/g);\n for (const f of packFunctions) {\n const tests = f.options['test'];\n const demo = f.options['demoPath'];\n if ((tests && Array.isArray(tests) && tests.length)) {\n for (let i = 0; i < tests.length; i++) {\n const res = tests[i].matchAll(reg);\n const map = {};\n Array.from(res).forEach((arr) => {\n if (arr[0].startsWith('skip'))\n map['skip'] = arr[1];\n else if (arr[0].startsWith('wait'))\n map['wait'] = parseInt(arr[2]);\n else if (arr[0].startsWith('cat'))\n map['cat'] = arr[3];\n else if (arr[0].startsWith('timeout'))\n map['timeout'] = parseInt(arr[4]);\n });\n const test = new Test((_h = map.cat) !== null && _h !== void 0 ? _h : autoTestsCatName, tests.length === 1 ? f.name : `${f.name} ${i + 1}`, () => __awaiter(this, void 0, void 0, function* () {\n const res = yield grok.functions.eval(addNamespace(tests[i], f));\n if (map.wait)\n yield delay(map.wait);\n // eslint-disable-next-line no-throw-literal\n if (typeof res === 'boolean' && !res)\n throw `Failed: ${tests[i]}, expected true, got ${res}`;\n }), { skipReason: map.skip, timeout: DG.Test.isInBenchmark ? (_j = map.benchmarkTimeout) !== null && _j !== void 0 ? _j : BENCHMARK_TIMEOUT : (_k = map.timeout) !== null && _k !== void 0 ? _k : STANDART_TIMEOUT });\n if (map.cat) {\n const cat = map.cat;\n if (moduleTests[cat] === undefined)\n moduleTests[cat] = { tests: [], clear: true };\n // only before/after can be defined in ts files tests under the category\n if (!moduleTests[cat].tests)\n moduleTests[cat].tests = [];\n moduleTests[cat].tests.push(test);\n }\n else\n moduleAutoTests.push(test);\n }\n }\n if (demo) {\n const wait = f.options['demoWait'] ? parseInt(f.options['demoWait']) : undefined;\n const test = new Test(demoCatName, f.friendlyName, () => __awaiter(this, void 0, void 0, function* () {\n yield delay(300);\n grok.shell.clearLastError();\n yield f.apply();\n yield delay(wait ? wait : 2000);\n const unhandled = yield grok.shell.lastError;\n if (unhandled)\n throw new Error(unhandled);\n }), { skipReason: f.options['demoSkip'] });\n moduleDemo.push(test);\n }\n if (f.hasTag('semTypeDetector')) {\n let detectorsTestData = testData;\n if (f.options['testData']) {\n detectorsTestData = yield grok.data.files.openTable(`System:AppData/${package_.nqName}/${f.options['testData']}`);\n }\n const test = new Test(detectorsCatName, f.friendlyName, () => __awaiter(this, void 0, void 0, function* () {\n const arr = [];\n console.log(`System:AppData/${package_.nqName}/${f.options['testData']}`);\n for (const col of detectorsTestData.clone().columns) {\n const res = yield f.apply([col]);\n arr.push(res || col.semType);\n }\n const resArr = arr.filter((i) => i);\n expect(resArr.length, 1);\n if (f.options['testDataColumnName'])\n expect(resArr[0], f.options['testDataColumnName']);\n }), { skipReason: f.options['skipTest'] });\n moduleDetectors.push(test);\n }\n }\n wasRegistered[packageId] = true;\n if (moduleAutoTests.length > 0)\n moduleTests[autoTestsCatName] = { tests: moduleAutoTests, clear: true };\n if (moduleDemo.length > 0)\n moduleTests[demoCatName] = { tests: moduleDemo, clear: true };\n if (moduleDetectors.length > 0)\n moduleTests[detectorsCatName] = { tests: moduleDetectors, clear: false };\n });\n}\nfunction redefineConsole() {\n const logs = [];\n console.log = (...args) => {\n logs.push(...args);\n stdLog(...args);\n };\n console.info = (...args) => {\n logs.push(...args);\n stdInfo(...args);\n };\n console.warn = (...args) => {\n logs.push(...args);\n stdWarn(...args);\n };\n console.error = (...args) => {\n logs.push(...args);\n stdError(...args);\n };\n return logs;\n}\nfunction resetConsole() {\n console.log = stdLog;\n console.info = stdInfo;\n console.warn = stdWarn;\n console.error = stdError;\n}\nexport function runTests(options) {\n var _a, _b;\n var _c;\n return __awaiter(this, void 0, void 0, function* () {\n const package_ = (options === null || options === void 0 ? void 0 : options.nodeOptions) ? options.nodeOptions.package : grok.functions.getCurrentCall().func.package;\n if (!package_)\n throw new Error('Can\\'t run tests outside of the package');\n const match = (_a = package_.packageOwner) === null || _a === void 0 ? void 0 : _a.match(/<([^>]*)>/);\n const packageOwner = match ? match[1] : '';\n if (package_ != undefined)\n yield initAutoTests(package_);\n const results = [];\n console.log(`Running tests...`);\n console.log(options);\n options !== null && options !== void 0 ? options : (options = {});\n (_b = (_c = options).testContext) !== null && _b !== void 0 ? _b : (_c.testContext = new TestContext());\n grok.shell.clearLastError();\n const logs = redefineConsole();\n yield invokeTests(tests, options);\n for (let r of results) {\n r.result = r.result.toString().replace(/\"/g, '\\'');\n if (r.logs != undefined)\n r.logs = r.logs.toString().replace(/\"/g, '\\'');\n }\n return results;\n function invokeCategoryMethod(method, category) {\n return __awaiter(this, void 0, void 0, function* () {\n let invokationResult = undefined;\n try {\n if (method !== undefined) {\n yield timeout(() => __awaiter(this, void 0, void 0, function* () {\n yield method();\n }), 100000, `before ${category}: timeout error`);\n }\n }\n catch (x) {\n invokationResult = yield getResult(x);\n }\n return invokationResult;\n });\n }\n function invokeTestsInCategory(category, options, isTargetCategory) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;\n return __awaiter(this, void 0, void 0, function* () {\n let t = (_a = category.tests) !== null && _a !== void 0 ? _a : [];\n const res = [];\n // let memoryUsageBefore = (window?.performance as any)?.memory?.usedJSHeapSize;\n const widgetsBefore = getWidgetsCountSafe();\n if (category.clear) {\n let skippingTests = isTargetCategory && options.skipToTest != undefined;\n for (let i = 0; i < t.length; i++) {\n if (t[i].options) {\n if (((_b = t[i].options) === null || _b === void 0 ? void 0 : _b.benchmark) === undefined) {\n if (!t[i].options)\n t[i].options = {};\n t[i].options.benchmark = (_c = category.benchmarks) !== null && _c !== void 0 ? _c : false;\n }\n }\n let test = t[i];\n if (options.test)\n if (options.test.toLowerCase() !== test.name.toLowerCase())\n continue;\n if (skippingTests) {\n if ((options === null || options === void 0 ? void 0 : options.skipToTest) != undefined && test.name.toLowerCase().trim() === (options === null || options === void 0 ? void 0 : options.skipToTest.toLowerCase().trim())) {\n // Found the target test, stop skipping after this one\n skippingTests = false;\n }\n else\n continue;\n }\n if (test === null || test === void 0 ? void 0 : test.options) {\n test.options.owner = (_g = (_f = (_e = (_d = t[i].options) === null || _d === void 0 ? void 0 : _d.owner) !== null && _e !== void 0 ? _e : category === null || category === void 0 ? void 0 : category.owner) !== null && _f !== void 0 ? _f : packageOwner) !== null && _g !== void 0 ? _g : '';\n }\n // let isGBEnable = (window as any).gc && test.options?.skipReason == undefined;\n // console.log(`********${isGBEnable}`);\n // if (isGBEnable)\n // await (window as any).gc();\n // memoryUsageBefore = (window?.performance as any)?.memory?.usedJSHeapSize;\n let testRun = yield execTest(test, options === null || options === void 0 ? void 0 : options.test, logs, DG.Test.isInBenchmark ? (_j = (_h = t[i].options) === null || _h === void 0 ? void 0 : _h.benchmarkTimeout) !== null && _j !== void 0 ? _j : BENCHMARK_TIMEOUT : (_l = (_k = t[i].options) === null || _k === void 0 ? void 0 : _k.timeout) !== null && _l !== void 0 ? _l : STANDART_TIMEOUT, package_.name, options.verbose);\n // if (isGBEnable)\n // await (window as any).gc();\n if (testRun) {\n res.push(Object.assign(Object.assign({}, testRun), { widgetsDifference: getWidgetsCountSafe() - widgetsBefore }));\n // Return early if returnOnFail is set and test failed (but ignore failure for the skipToTest test itself)\n if (options.returnOnFail && options.skipToTest !== test.name && !testRun.success && !testRun.skipped)\n return res;\n }\n // res.push({ ...testRun, memoryDelta: (window?.performance as any)?.memory?.usedJSHeapSize - memoryUsageBefore, widgetsDelta: getWidgetsCountSafe() - widgetsBefore });\n if (!options.nodeOptions) {\n grok.shell.closeAll();\n DG.Balloon.closeAll();\n }\n }\n }\n else {\n let skippingTests = isTargetCategory && options.skipToTest != undefined;\n for (let i = 0; i < t.length; i++) {\n let test = t[i];\n if (options.test)\n if (options.test.toLowerCase() !== test.name.toLowerCase())\n continue;\n if (skippingTests) {\n if ((options === null || options === void 0 ? void 0 : options.skipToTest) != undefined && test.name.toLowerCase().trim() === (options === null || options === void 0 ? void 0 : options.skipToTest.toLowerCase().trim())) {\n // Found the target test, stop skipping after this one\n skippingTests = false;\n }\n continue; // Skip this test (including the target)\n }\n if (test === null || test === void 0 ? void 0 : test.options) {\n test.options.owner = (_q = (_p = (_o = (_m = t[i].options) === null || _m === void 0 ? void 0 : _m.owner) !== null && _o !== void 0 ? _o : category === null || category === void 0 ? void 0 : category.owner) !== null && _p !== void 0 ? _p : packageOwner) !== null && _q !== void 0 ? _q : '';\n }\n // let isGBEnable = (window as any).gc && test.options?.skipReason == undefined;\n // console.log(`********${isGBEnable}`);\n // if (isGBEnable)\n // await (window as any).gc();\n // memoryUsageBefore = (window?.performance as any)?.memory?.usedJSHeapSize;\n let testRun = yield execTest(test, options === null || options === void 0 ? void 0 : options.test, logs, DG.Test.isInBenchmark ? (_s = (_r = t[i].options) === null || _r === void 0 ? void 0 : _r.benchmarkTimeout) !== null && _s !== void 0 ? _s : BENCHMARK_TIMEOUT : (_t = t[i].options) === null || _t === void 0 ? void 0 : _t.timeout, package_.name, options.verbose);\n // if (isGBEnable)\n // await (window as any).gc();\n if (testRun) {\n res.push(Object.assign(Object.assign({}, testRun), { widgetsDifference: getWidgetsCountSafe() - widgetsBefore }));\n // Return early if returnOnFail is set and test failed (but ignore failure for the skipToTest test itself)\n if (options.returnOnFail && options.skipToTest !== test.name && !testRun.success && !testRun.skipped)\n return res;\n }\n // res.push({ ...testRun, memoryDelta: (window?.performance as any)?.memory?.usedJSHeapSize - memoryUsageBefore, widgetsDifference: getWidgetsCountSafe() - widgetsBefore });\n }\n }\n return res;\n });\n }\n function getWidgetsCountSafe() {\n var _a;\n if (typeof process !== 'undefined')\n return 0;\n let length = -1;\n try {\n length = DG.Widget.getAll().length;\n }\n catch (e) {\n console.warn((_a = e.message) !== null && _a !== void 0 ? _a : e);\n }\n return length;\n }\n function invokeTests(categoriesToInvoke, options) {\n var _a, _b, _c, _d, _e, _f;\n return __awaiter(this, void 0, void 0, function* () {\n try {\n let skippingCategories = (options === null || options === void 0 ? void 0 : options.skipToCategory) != undefined;\n let isTargetCategory = false;\n for (const [key, value] of Object.entries(categoriesToInvoke)) {\n if ((_a = options.exclude) === null || _a === void 0 ? void 0 : _a.some((c) => key.startsWith(c)))\n continue;\n if ((options === null || options === void 0 ? void 0 : options.category) != null && !key.toLowerCase().startsWith(options === null || options === void 0 ? void 0 : options.category.toLowerCase().trim()))\n continue;\n if (skippingCategories) {\n if (isTargetCategory)\n skippingCategories = false;\n else {\n if ((options === null || options === void 0 ? void 0 : options.skipToCategory) != null && key.toLowerCase().trim() === (options === null || options === void 0 ? void 0 : options.skipToCategory.toLowerCase().trim())) {\n isTargetCategory = true;\n }\n else {\n // Haven't found the target category yet, keep skipping\n continue;\n }\n }\n }\n //@ts-ignore\n const skipped = (_b = value.tests) === null || _b === void 0 ? void 0 : _b.every((t) => {\n var _a;\n return ((_a = t.options) === null || _a === void 0 ? void 0 : _a.skipReason)\n || ((options === null || options === void 0 ? void 0 : options.test) != null && options.test.toLowerCase() !== t.name.toLowerCase());\n });\n if (!skipped) {\n //@ts-ignore\n const skippedCount = ((_c = value.tests) !== null && _c !== void 0 ? _c : []).filter((t) => { var _a; return ((_a = t.options) === null || _a === void 0 ? void 0 : _a.skipReason) || ((options === null || options === void 0 ? void 0 : options.test) != null && options.test.toLowerCase() !== t.name.toLowerCase()); }).length;\n stdLog(`Package testing: Started {{${key}}}${skippedCount > 0 ? ` skipped {{${skippedCount}}}` : ''}`);\n value.beforeStatus = yield invokeCategoryMethod(value.before, key);\n }\n let t = (_d = value.tests) !== null && _d !== void 0 ? _d : [];\n if (options.stressTest) {\n t = t.filter((e) => { var _a; return (_a = e.options) === null || _a === void 0 ? void 0 : _a.stressTest; });\n t = shuffle(t);\n }\n if (((_f = (_e = options.tags) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0) > 0) {\n t = t.filter((e) => { var _a, _b; return (_b = (_a = e.options) === null || _a === void 0 ? void 0 : _a.tags) === null || _b === void 0 ? void 0 : _b.some(tag => { var _a; return ((_a = options === null || options === void 0 ? void 0 : options.tags) !== null && _a !== void 0 ? _a : []).includes(tag); }); });\n }\n let res;\n if (value.beforeStatus) {\n res = Array.from(t.map((testElem) => {\n return {\n date: new Date().toISOString(),\n category: key,\n name: testElem.name,\n success: false,\n result: 'before() failed',\n ms: 0,\n skipped: false,\n logs: '',\n owner: packageOwner,\n package: package_.name,\n widgetsDifference: 0,\n flaking: DG.Test.isReproducing\n };\n }));\n res.forEach((test) => __awaiter(this, void 0, void 0, function* () { return yield grok.shell.reportTest('package', test); }));\n }\n else\n res = yield invokeTestsInCategory(value, options, skippingCategories);\n const data = res.filter((d) => d.result != 'skipped');\n if (!skipped)\n value.afterStatus = yield invokeCategoryMethod(value.after, key);\n // Clear after category\n // grok.shell.closeAll();\n // DG.Balloon.closeAll();\n if (value.afterStatus) {\n stdLog(`Package testing: Category after() {{${key}}} failed`);\n stdLog(`Package testing: Result for {{${key}}} after: ${value.afterStatus}`);\n data.push({\n date: new Date().toISOString(),\n category: key,\n name: 'after',\n success: false,\n result: value.afterStatus,\n ms: 0,\n skipped: false,\n logs: '',\n owner: packageOwner,\n package: package_.name,\n widgetsDifference: 0,\n flaking: DG.Test.isReproducing\n });\n }\n if (value.beforeStatus) {\n stdLog(`Package testing: Category before() {{${key}}} failed`);\n stdLog(`Package testing: Result for {{${key}}} before: ${value.beforeStatus}`);\n data.push({\n date: new Date().toISOString(),\n category: key,\n name: 'before',\n success: false,\n result: value.beforeStatus,\n ms: 0,\n skipped: false,\n logs: '',\n owner: packageOwner,\n package: package_.name,\n widgetsDifference: 0,\n flaking: DG.Test.isReproducing\n });\n }\n results.push(...data);\n // If returnOnFail is set and a test failed (other than skipToTest), stop processing more categories\n if (options.returnOnFail && data.some((d) => !d.success && !d.skipped && d.name !== options.skipToTest))\n break;\n }\n }\n finally {\n resetConsole();\n }\n if (options.testContext.catchUnhandled && (!DG.Test.isInBenchmark)) {\n yield delay(1000);\n const error = yield grok.shell.lastError;\n if (error != undefined) {\n const params = {\n logs: '',\n date: new Date().toISOString(),\n category: 'Unhandled exceptions',\n name: 'Exception',\n result: error !== null && error !== void 0 ? error : '',\n success: !error,\n ms: 0,\n skipped: false,\n owner: packageOwner !== null && packageOwner !== void 0 ? packageOwner : '',\n 'package': package_.name,\n widgetsDifference: 0\n };\n stdLog(`Package testing: Unhandled Exception: ${error}`);\n results.push(Object.assign(Object.assign({}, params), { 'flaking': DG.Test.isReproducing && !error }));\n params.package = package_.name;\n yield grok.shell.reportTest('package', params);\n }\n }\n });\n }\n });\n}\nfunction getResult(x) {\n return __awaiter(this, void 0, void 0, function* () {\n return `${x.toString()}\\n${x.stack ? (yield DG.Logger.translateStackTrace(x.stack)) : ''}`;\n });\n}\nfunction execTest(t, predicate, logs, testTimeout, packageName, verbose) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;\n return __awaiter(this, void 0, void 0, function* () {\n logs.length = 0;\n let r;\n let type = 'package';\n const filter = predicate != undefined && (t.name.toLowerCase() !== predicate.toLowerCase());\n let skip = ((_a = t.options) === null || _a === void 0 ? void 0 : _a.skipReason) || filter;\n let skipReason = filter ? 'skipped' : (_b = t.options) === null || _b === void 0 ? void 0 : _b.skipReason;\n if (DG.Test.isInBenchmark && !((_c = t.options) === null || _c === void 0 ? void 0 : _c.benchmark)) {\n stdLog(`Package testing: Skipped {{${t.category}}} {{${t.name}}} doesnt available in benchmark mode`);\n return undefined;\n }\n if (skip && !DG.Test.isInBenchmark)\n stdLog(`Package testing: Skipped {{${t.category}}} {{${t.name}}}`);\n if (!skip)\n stdLog(`Package testing: Started {{${t.category}}} {{${t.name}}}`);\n const start = Date.now();\n const startDate = new Date(start).toISOString();\n try {\n if (skip)\n r = { name: t.name, owner: (_e = (_d = t.options) === null || _d === void 0 ? void 0 : _d.owner) !== null && _e !== void 0 ? _e : '', category: t.category, logs: '', date: startDate, success: true, result: skipReason, ms: 0, skipped: true, package: packageName !== null && packageName !== void 0 ? packageName : '', flaking: DG.Test.isReproducing };\n else {\n let timeout_ = testTimeout !== null && testTimeout !== void 0 ? testTimeout : STANDART_TIMEOUT;\n if (DG.Test.isProfiling)\n console.profile(`${t.category}: ${t.name}`);\n r = { name: t.name, owner: (_g = (_f = t.options) === null || _f === void 0 ? void 0 : _f.owner) !== null && _g !== void 0 ? _g : '', category: t.category, logs: '', date: startDate, success: true, result: (_h = (yield timeout(t.test, timeout_)).toString()) !== null && _h !== void 0 ? _h : 'OK', ms: 0, skipped: false, package: packageName !== null && packageName !== void 0 ? packageName : '', flaking: DG.Test.isReproducing };\n if (DG.Test.isProfiling) {\n console.profileEnd(`${t.category}: ${t.name}`);\n grok.shell.info(`Profiling of ${t.category}: ${t.name} finished \\n Please ensure that you have opened DevTools (F12) / Performance panel before test starts.`);\n }\n }\n }\n catch (x) {\n stdError(x);\n r = { name: t.name, owner: (_k = (_j = t.options) === null || _j === void 0 ? void 0 : _j.owner) !== null && _k !== void 0 ? _k : '', category: t.category, logs: '', date: startDate, success: false, result: yield getResult(x), ms: 0, skipped: false, package: packageName !== null && packageName !== void 0 ? packageName : '', flaking: false };\n }\n if (((_l = t.options) === null || _l === void 0 ? void 0 : _l.isAggregated) && r.result.constructor === DG.DataFrame) {\n const col = r.result.col('success');\n if (col)\n r.success = col.stats.sum === col.length;\n if (!verbose) {\n const df = r.result;\n df.columns.remove('stack');\n df.rows.removeWhere((r) => r.get('success'));\n r.result = df;\n }\n r.result = r.result.toCsv();\n }\n r.logs = logs.join('\\n');\n r.ms = Date.now() - start;\n if (!skip)\n stdLog(`Package testing: Finished {{${t.category}}} {{${t.name}}} with {{${r.success ? 'success' : 'error'}}} for ${r.ms} ms`);\n if (!r.success) {\n stdLog(`Package testing: Result for {{${t.category}}} {{${t.name}}}: ${r.result}`);\n }\n r.category = t.category;\n r.name = t.name;\n r.owner = (_o = (_m = t.options) === null || _m === void 0 ? void 0 : _m.owner) !== null && _o !== void 0 ? _o : '';\n if (!filter) {\n let params = {\n 'success': r.success, 'result': r.result, 'ms': r.ms, 'date': r.date,\n 'skipped': r.skipped, 'category': t.category, 'name': t.name, 'logs': r.logs, 'owner': r.owner,\n 'flaking': DG.Test.isReproducing && r.success,\n 'package': r.package\n };\n if (r.result.constructor == Object) {\n const res = Object.keys(r.result).reduce((acc, k) => (Object.assign(Object.assign({}, acc), { ['result.' + k]: r.result[k] })), {});\n params = Object.assign(Object.assign({}, params), res);\n }\n if (params.result instanceof DG.DataFrame)\n params.result = JSON.stringify((_p = params.result) === null || _p === void 0 ? void 0 : _p.toJson()) || '';\n yield grok.shell.reportTest(type, params);\n }\n return r;\n });\n}\nexport function shuffle(array) {\n const newArr = array.slice();\n newArr.sort(() => Math.random() - 0.5);\n return newArr;\n}\n/* Waits [ms] milliseconds */\nexport function delay(ms) {\n return __awaiter(this, void 0, void 0, function* () {\n yield new Promise((r) => setTimeout(r, ms));\n });\n}\nexport function awaitCheck(checkHandler, error = 'Timeout exceeded', wait = 500, interval = 50) {\n return __awaiter(this, void 0, void 0, function* () {\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n clearInterval(intervalId);\n reject(new Error(error));\n }, wait);\n // @ts-ignore\n const intervalId = setInterval(() => {\n if (checkHandler()) {\n clearInterval(intervalId);\n resolve(null);\n }\n }, interval);\n });\n });\n}\n// Returns test execution result or an error in case of timeout\nexport function timeout(func, testTimeout, timeoutReason = 'EXECUTION TIMEOUT') {\n return __awaiter(this, void 0, void 0, function* () {\n let timeout = null;\n const timeoutPromise = new Promise((_, reject) => {\n timeout = setTimeout(() => {\n // eslint-disable-next-line prefer-promise-reject-errors\n reject(timeoutReason);\n }, testTimeout);\n });\n try {\n return yield Promise.race([func(), timeoutPromise]);\n }\n finally {\n if (timeout)\n clearTimeout(timeout);\n }\n });\n}\nexport function isDialogPresent(dialogTitle) {\n const dialogs = DG.Dialog.getOpenDialogs();\n for (let i = 0; i < dialogs.length; i++) {\n if (dialogs[i].title == dialogTitle)\n return true;\n }\n return false;\n}\n/** Expects an asynchronous {@link action} to throw an exception. Use {@link check} to perform\n * deeper inspection of the exception if necessary.\n * @param {function(): Promise<void>} action\n * @param {function(any): boolean} check\n * @return {Promise<void>}\n */\nexport function expectExceptionAsync(action, check) {\n return __awaiter(this, void 0, void 0, function* () {\n let caught = false;\n let checked = false;\n try {\n yield action();\n }\n catch (e) {\n caught = true;\n checked = !check || check(e);\n }\n finally {\n if (!caught)\n throw new Error('An exception is expected but not thrown');\n if (!checked)\n throw new Error('An expected exception is thrown, but it does not satisfy the condition');\n }\n });\n}\nconst catDF = DG.DataFrame.fromColumns([DG.Column.fromStrings('col', ['val1', 'val2', 'val3'])]);\n/**\n * Universal test for viewers. It search viewers in DOM by tags: canvas, svg, img, input, h1, a\n * @param {string} v Viewer name\n * @param {_DG.DataFrame} df Dataframe to use. Should have at least 3 rows\n * @param {boolean} options.detectSemanticTypes Specify whether to detect semantic types or not\n * @param {boolean} options.readOnly If set to true, the dataframe will not be modified during the test\n * @param {boolean} options.arbitraryDfTest If set to false, test on arbitrary dataframe\n * (one categorical column) will not be performed\n * @param {object} options List of options (optional)\n * @return {Promise<void>} The test is considered successful if it completes without errors\n */\nexport function testViewer(v, df, options) {\n var _a;\n return __awaiter(this, void 0, void 0, function* () {\n const packageName = (_a = options === null || options === void 0 ? void 0 : options.packageName) !== null && _a !== void 0 ? _a : '';\n if (options === null || options === void 0 ? void 0 : options.detectSemanticTypes)\n yield grok.data.detectSemanticTypes(df);\n const tv = grok.shell.addTableView(df);\n try {\n //1. Open, do nothing and close\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded);\n //in case viewer with async rendering - wait for render to complete\n if (options === null || options === void 0 ? void 0 : options.awaitViewer)\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, undefined, options.awaitViewer);\n //2. Open viewer, run selection, filter, etc. and close\n if (!(options === null || options === void 0 ? void 0 : options.readOnly)) {\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, selectFilterChangeCurrent);\n if (options === null || options === void 0 ? void 0 : options.awaitViewer)\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, selectFilterChangeCurrent, options.awaitViewer);\n }\n //2. Open viewer, change options, save layout and close\n let propsAndLayout = null;\n propsAndLayout = yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, changeOptionsSaveLayout);\n if (options === null || options === void 0 ? void 0 : options.awaitViewer)\n propsAndLayout = yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, changeOptionsSaveLayout, options.awaitViewer);\n //3. Load layout\n yield testViewerInternal(tv, v, packageName, grok.events.onViewLayoutApplied, loadLayout, undefined, propsAndLayout === null || propsAndLayout === void 0 ? void 0 : propsAndLayout.layout, { savedProps: propsAndLayout === null || propsAndLayout === void 0 ? void 0 : propsAndLayout.savedProps });\n if (options === null || options === void 0 ? void 0 : options.awaitViewer)\n yield testViewerInternal(tv, v, packageName, grok.events.onViewLayoutApplied, loadLayout, options.awaitViewer, propsAndLayout === null || propsAndLayout === void 0 ? void 0 : propsAndLayout.layout, { savedProps: propsAndLayout === null || propsAndLayout === void 0 ? void 0 : propsAndLayout.savedProps });\n //4. Open viewer on arbitary dataset\n if ((options === null || options === void 0 ? void 0 : options.arbitraryDfTest) !== false) {\n tv.dataFrame = catDF;\n yield delay(50);\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded);\n if (options === null || options === void 0 ? void 0 : options.awaitViewer)\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, undefined, options.awaitViewer);\n }\n //5. Call postponed filtering\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, filterAsync);\n if (options === null || options === void 0 ? void 0 : options.awaitViewer)\n yield testViewerInternal(tv, v, packageName, grok.events.onViewerAdded, filterAsync, options.awaitViewer);\n }\n finally {\n // closeAll() is handling by common test workflow\n // grok.shell.closeAll();\n // DG.Balloon.closeAll();\n }\n });\n}\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBS0EsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRTdDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLHlCQUF5QixFQUFFLGtCQUFrQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdEksTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLENBQUM7QUFDL0IsTUFBTSxpQkFBaUIsR0FBRyxRQUFRLENBQUM7QUFFbkMsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDekMsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDM0MsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDM0MsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7QUFFN0MsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUVkLEVBQUUsQ0FBQztBQUVQLE1BQU0sZ0JBQWdCLEdBQUcsWUFBWSxDQUFDO0FBQ3RDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQztBQUMzQixNQUFNLGdCQUFnQixHQUFHLFdBQVcsQ0FBQztBQUNyQyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUM7QUFDM0IsTUFBTSxhQUFhLEdBQStCLEVBQUUsQ0FBQztBQUNyRCxNQUFNLENBQUMsSUFBSSxlQUF1QixDQUFDO0FBRW5DLE1BQU0sS0FBVyxNQUFNLENBS3RCO0FBTEQsV0FBaUIsTUFBTTtJQUNyQixTQUFnQixPQUFPLENBQUMsS0FBVSxFQUFFLElBQWE7UUFDL0MsSUFBSSxLQUFLLElBQUksSUFBSTtZ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QyxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUNyRixJQUFJLE9BQU8sYUFBUCxPQUFPLHVCQUFQLE9BQU8sQ0FBRSxXQUFXO2dCQUN0QixNQUFNLGtCQUFrQixDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLFdBQVcsRUFBRSxPQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7U0FFOUc7Z0JBQVM7WUFDUixpREFBaUQ7WUFDakQseUJBQXlCO1lBQ3pCLHlCQUF5QjtTQUMxQjs7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlICogYXMgX2dyb2sgZnJvbSAnZGF0YWdyb2stYXBpL2dyb2snO1xuaW1wb3J0IHR5cGUgKiBhcyBfREcgZnJvbSAnZGF0YWdyb2stYXBpL2RnJztcbmRlY2xhcmUgbGV0IGdyb2s6IHR5cGVvZiBfZ3JvaywgREc6IHR5cGVvZiBfREc7XG5cbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRlc3REYXRhIH0gZnJvbSAnLi9kYXRhZnJhbWUtdXRpbHMnO1xuaW1wb3J0IFRpbWVvdXQgPSBOb2RlSlMuVGltZW91dDtcbmltcG9ydCB7IGNoYW5nZU9wdGlvbnNTYXZlTGF5b3V0LCBmaWx0ZXJBc3luYywgbG9hZExheW91dCwgc2VsZWN0RmlsdGVyQ2hhbmdlQ3VycmVudCwgdGVzdFZpZXdlckludGVybmFsIH0gZnJvbSAnLi90ZXN0LXZpZXdlci11dGlscyc7XG5cbmNvbnN0IFNUQU5EQVJUX1RJTUVPVVQgPSAzMDAwMDtcbmNvbnN0IEJFTkNITUFSS19USU1FT1VUID0gMTA4MDAwMDA7XG5cbmNvbnN0IHN0ZExvZyA9IGNvbnNvbGUubG9nLmJpbmQoY29uc29sZSk7XG5jb25zdCBzdGRJbmZvID0gY29uc29sZS5pbmZvLmJpbmQoY29uc29sZSk7XG5jb25zdCBzdGRXYXJuID0gY29uc29sZS53YXJuLmJpbmQoY29uc29sZSk7XG5jb25zdCBzdGRFcnJvciA9IGNvbnNvbGUuZXJyb3IuYmluZChjb25zb2xlKTtcblxuZXhwb3J0IGNvbnN0IHRlc3RzOiB7XG4gIFtrZXk6IHN0cmluZ106IENhdGVnb3J5XG59ID0ge307XG5cbmNvbnN0IGF1dG9UZXN0c0NhdE5hbWUgPSAnQXV0byBUZXN0cyc7XG5jb25zdCBkZW1vQ2F0TmFtZSA9ICdEZW1vJztcbmNvbnN0IGRldGVjdG9yc0NhdE5hbWUgPSAnRGV0ZWN0b3JzJztcbmNvbnN0IGNvcmVDYXROYW1lID0gJ0NvcmUnO1xuY29uc3Qgd2FzUmVnaXN0ZXJlZDogeyBba2V5OiBzdHJpbmddOiBib29sZWFuIH0gPSB7fTtcbmV4cG9ydCBsZXQgY3VycmVudENhdGVnb3J5OiBzdHJpbmc7XG5cbmV4cG9ydCBuYW1lc3BhY2UgYXNzdXJlIHtcbiAgZXhwb3J0IGZ1bmN0aW9uIG5vdE51bGwodmFsdWU6IGFueSwgbmFtZT86IHN0cmluZykge1xuICAgIGlmICh2YWx1ZSA9PSBudWxsKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGAke25hbWUgPT0gbnVsbCA/ICdWYWx1ZScgOiBuYW1lfSBub3QgZGVmaW5lZGApO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVzdE9wdGlvbnMge1xuICB0aW1lb3V0PzogbnVtYmVyO1xuICBiZW5jaG1hcmtXYXJuVGltZW91dD86IG51bWJlcjtcbiAgYmVuY2htYXJrVGltZW91dD86IG51bWJlcjtcbiAgdW5oYW5kbGVkRXhjZXB0aW9uVGltZW91dD86IG51bWJlcjtcbiAgc2tpcFJlYXNvbj86IHN0cmluZztcbiAgaXNBZ2dyZWdhdGVkPzogYm9vbGVhbjtcbiAgYmVuY2htYXJrPzogYm9vbGVhbjtcbiAgc3RyZXNzVGVzdD86IGJvb2xlYW47XG4gIG93bmVyPzogc3RyaW5nO1xuICB0YWdzPzogc3RyaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVzdFJlc3VsdCB7XG4gIGRhdGU6IHN0cmluZztcbiAgY2F0ZWdvcnk6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBzdWNjZXNzOiBib29sZWFuO1xuICByZXN1bHQ6IGFueTtcbiAgbXM6IG51bWJlcjtcbiAgc2tpcHBlZDogYm9vbGVhbjtcbiAgbG9nczogc3RyaW5nO1xuICBvd25lcjogc3RyaW5nO1xuICBwYWNrYWdlOiBzdHJpbmc7XG4gIGZsYWtpbmc6IGJvb2xlYW47XG59XG5cblxuZXhwb3J0IGludGVyZmFjZSBUZXN0UmVzdWx0RXh0ZW5kZWQgZXh0ZW5kcyBUZXN0UmVzdWx0e1xuICB3aWRnZXRzRGlmZmVyZW5jZTogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhdGVnb3J5T3B0aW9ucyB7XG4gIGNsZWFyPzogYm9vbGVhbjtcbiAgdGltZW91dD86IG51bWJlcjtcbiAgYmVuY2htYXJrcz86IGJvb2xlYW47XG4gIHN0cmVzc1Rlc3RzPzogYm9vbGVhbjtcbiAgb3duZXI/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBUZXN0Q29udGV4dCB7XG4gIHN0cmVzc1Rlc3Q/OiBib29sZWFuO1xuICBjYXRjaFVuaGFuZGxlZCA9IHRydWU7XG4gIHJlcG9ydCA9IGZhbHNlO1xuICByZXR1cm5PbkZhaWwgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihjYXRjaFVuaGFuZGxlZD86IGJvb2xlYW4sIHJlcG9ydD86IGJvb2xlYW4sIHJldHVybk9uRmFpbD86IGJvb2xlYW4pIHtcbiAgICBpZiAoY2F0Y2hVbmhhbmRsZWQgIT09IHVuZGVmaW5lZCkgdGhpcy5jYXRjaFVuaGFuZGxlZCA9IGNhdGNoVW5oYW5kbGVkO1xuICAgIGlmIChyZXBvcnQgIT09IHVuZGVmaW5lZCkgdGhpcy5yZXBvcnQgPSByZXBvcnQ7XG4gICAgaWYgKHJldHVybk9uRmFpbCAhPT0gdW5kZWZpbmVkKSB0aGlzLnJldHVybk9uRmFpbCA9IHJldHVybk9uRmFpbDtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIFRlc3Qge1xuICB0ZXN0OiAoKSA9PiBQcm9taXNlPGFueT47XG4gIG5hbWU6IHN0cmluZztcbiAgY2F0ZWdvcnk6IHN0cmluZztcbiAgb3B0aW9ucz86IFRlc3RPcHRpb25zO1xuXG4gIGNvbnN0cnVjdG9yKGNhdGVnb3J5OiBzdHJpbmcsIG5hbWU6IHN0cmluZywgdGVzdDogKCkgPT4gUHJvbWlzZTxhbnk+LCBvcHRpb25zPzogVGVzdE9wdGlvbnMpIHtcbiAgICB0aGlzLmNhdGVnb3J5ID0gY2F0ZWdvcnk7XG4gICAgdGhpcy5uYW1lID0gbmFtZTtcbiAgICBvcHRpb25zID8/PSB7fTtcbiAgICBvcHRpb25zLnRpbWVvdXQgPz89IFNUQU5EQVJUX1RJTUVPVVQ7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICB0aGlzLnRlc3QgPSBhc3luYyAoKTogUHJvbWlzZTxhbnk+ID0+IHtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyAocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCByZXN1bHQgPSAnJztcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoREcuVGVzdC5pc0luRGVidWcpXG4gICAgICAgICAgICBkZWJ1Z2dlcjtcblxuICAgICAgICAgIGxldCByZXMgPSBhd2FpdCB0ZXN0KCk7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJlc3VsdCA9IHJlcz8udG9TdHJpbmcoKSA/PyAnJztcbiAgICAgICAgICB9XG4gICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJlc3VsdCA9ICdDYW5cXCd0IGNvbnZlcnQgdGVzdFxcJ3MgcmVzdWx0IHRvIHN0cmluZyc7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBDYW5cXCd0IGNvbnZlcnQgdGVzdFxcJ3MgcmVzdWx0IHRvIHN0cmluZyBpbiB0aGUgJHt0aGlzLmNhdGVnb3J5fToke3RoaXMubmFtZX0gdGVzdGApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgICB9XG4gICAgICAgIHJlc29sdmUocmVzdWx0KTtcbiAgICAgIH0pO1xuICAgIH07XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIENhdGVnb3J5IHtcbiAgdGVzdHM/OiBUZXN0W107XG4gIGJlZm9yZT86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIGFmdGVyPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcblxuICBiZWZvcmVTdGF0dXM/OiBzdHJpbmc7XG4gIGFmdGVyU3RhdHVzPzogc3RyaW5nO1xuICBjbGVhcj86IGJvb2xlYW47XG4gIHRpbWVvdXQ/OiBudW1iZXI7XG4gIGJlbmNobWFya3M/OiBib29sZWFuO1xuICBiZW5jaG1hcmtUaW1lb3V0PzogbnVtYmVyO1xuICBzdHJlc3NUZXN0cz86IGJvb2xlYW47XG4gIG93bmVyPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgTm9kZVRlc3RFeGVjdXRpb25PcHRpb25zIHtcbiAgcGFja2FnZSE6IF9ERy5QYWNrYWdlO1xufVxuXG5leHBvcnQgY2xhc3MgVGVzdEV4ZWN1dGlvbk9wdGlvbnMge1xuICBjYXRlZ29yeT86IHN0cmluZztcbiAgdGVzdD86IHN0cmluZztcbiAgdGVzdENvbnRleHQ/OiBUZXN0Q29udGV4dDtcbiAgZXhjbHVkZT86IHN0cmluZ1tdO1xuICB2ZXJib3NlPzogYm9vbGVhbjtcbiAgc3RyZXNzVGVzdD86IGJvb2xlYW47XG4gIHRhZ3M/OiBzdHJpbmdbXTtcbiAgbm9kZU9wdGlvbnM/OiBOb2RlVGVzdEV4ZWN1dGlvbk9wdGlvbnM7XG4gIHNraXBUb0NhdGVnb3J5Pzogc3RyaW5nO1xuICBza2lwVG9UZXN0Pzogc3RyaW5nO1xuICByZXR1cm5PbkZhaWw/OiBib29sZWFuO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdGVzdEV2ZW50PFQ+KGV2ZW50OiBPYnNlcnZhYmxlPFQ+LFxuICBoYW5kbGVyOiAoYXJnczogVCkgPT4gdm9pZCwgdHJpZ2dlcjogKCkgPT4gdm9pZCwgbXM6IG51bWJlciA9IDAsIHJlYXNvbjogc3RyaW5nID0gYHRpbWVvdXRgXG4pOiBQcm9taXNlPGFueT4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHN1YiA9IGV2ZW50LnN1YnNjcmliZSgoYXJnczogVCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaGFuZGxlcihhcmdzKTtcbiAgICAgICAgcmVzb2x2ZSgnT0snKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgc3ViLnVuc3Vic2NyaWJlKCk7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBjb25zdCB0aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBzdWIudW5zdWJzY3JpYmUoKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcmVmZXItcHJvbWlzZS1yZWplY3QtZXJyb3JzXG4gICAgICByZWplY3QocmVhc29uKTtcbiAgICB9LCBtcyk7XG4gICAgdHJpZ2dlcigpO1xuICB9KTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRlc3RFdmVudEFzeW5jPFQ+KGV2ZW50OiBPYnNlcnZhYmxlPFQ+LFxuICBoYW5kbGVyOiAoYXJnczogVCkgPT4gUHJvbWlzZTx2b2lkPiwgdHJpZ2dlcjogKCkgPT4gdm9pZCwgbXM6IG51bWJlciA9IDAsIHJlYXNvbjogc3RyaW5nID0gYHRpbWVvdXRgXG4pOiBQcm9taXNlPGFueT4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHN1YiA9IGV2ZW50LnN1YnNjcmliZSgoYXJnczogVCkgPT4ge1xuICAgICAgaGFuZGxlcihhcmdzKS50aGVuKCgpID0+IHtcbiAgICAgICAgcmVzb2x2ZSgnT0snKTtcbiAgICAgIH0pLmNhdGNoKChlKSA9PiB7XG4gICAgICAgIHJlamVjdChlKTtcbiAgICAgIH0pLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICBzdWIudW5zdWJzY3JpYmUoKTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gICAgY29uc3QgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgc3ViLnVuc3Vic2NyaWJlKCk7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLXByb21pc2UtcmVqZWN0LWVycm9yc1xuICAgICAgcmVqZWN0KHJlYXNvbik7XG4gICAgfSwgbXMpO1xuICAgIHRyaWdnZXIoKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0ZXN0KG5hbWU6IHN0cmluZywgdGVzdDogKCkgPT4gUHJvbWlzZTxhbnk+LCBvcHRpb25zPzogVGVzdE9wdGlvbnMpOiB2b2lkIHtcbiAgaWYgKHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0gPT0gdW5kZWZpbmVkKVxuICAgIHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0gPSB7fTtcbiAgaWYgKHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0udGVzdHMgPT0gdW5kZWZpbmVkKVxuICAgIHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0udGVzdHMgPSBbXTtcbiAgdGVzdHNbY3VycmVudENhdGVnb3J5XS50ZXN0cyEucHVzaChuZXcgVGVzdChjdXJyZW50Q2F0ZWdvcnksIG5hbWUsIHRlc3QsIG9wdGlvbnMpKTtcbn1cblxuLyogVGVzdHMgdHdvIG9iamVjdHMgZm9yIGVxdWFsaXR5LCB0aHJvd3MgYW4gZXhjZXB0aW9uIGlmIHRoZXkgYXJlIG5vdCBlcXVhbC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHBlY3QoYWN0dWFsOiBhbnksIGV4cGVjdGVkOiBhbnkgPSB0cnVlLCBlcnJvcj86IHN0cmluZyk6IHZvaWQge1xuICBpZiAoZXJyb3IpXG4gICAgZXJyb3IgPSBgJHtlcnJvcn0sIGA7XG4gIGVsc2UgZXJyb3IgPSAnJztcbiAgaWYgKGFjdHVhbCAhPT0gZXhwZWN0ZWQpXG4gICAgdGhyb3cgbmV3IEVycm9yKGAke2Vycm9yfUV4cGVjdGVkIFwiJHtleHBlY3RlZH1cIiwgZ290IFwiJHthY3R1YWx9XCJgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGV4cGVjdEZsb2F0KGFjdHVhbDogbnVtYmVyLCBleHBlY3RlZDogbnVtYmVyLCB0b2xlcmFuY2UgPSAwLjAwMSwgZXJyb3I/OiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKChhY3R1YWwgPT09IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSAmJiBleHBlY3RlZCA9PT0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZKSB8fFxuICAgIChhY3R1YWwgPT09IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSAmJiBleHBlY3RlZCA9PT0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZKSB8fFxuICAgIChhY3R1YWwgPT09IE51bWJlci5OYU4gJiYgZXhwZWN0ZWQgPT09IE51bWJlci5OYU4pIHx8IChpc05hTihhY3R1YWwpICYmIGlzTmFOKGV4cGVjdGVkKSkpXG4gICAgcmV0dXJuO1xuICBjb25zdCBhcmVFcXVhbCA9IE1hdGguYWJzKGFjdHVhbCAtIGV4cGVjdGVkKSA8IHRvbGVyYW5jZTtcbiAgZXhwZWN0KGFyZUVxdWFsLCB0cnVlLCBgJHtlcnJvciA/PyAnJ30gKHRvbGVyYW5jZSA9ICR7dG9sZXJhbmNlfTsgYSA9ICR7YWN0dWFsfSwgZSA9ICR7ZXhwZWN0ZWR9KWApO1xuICBpZiAoIWFyZUVxdWFsKVxuICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtleHBlY3RlZH0sIGdvdCAke2FjdHVhbH0gKHRvbGVyYW5jZSA9ICR7dG9sZXJhbmNlfSlgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGV4cGVjdFRhYmxlKGFjdHVhbDogX0RHLkRhdGFGcmFtZSwgZXhwZWN0ZWQ6IF9ERy5EYXRhRnJhbWUsIGVycm9yPzogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGV4cGVjdGVkUm93Q291bnQgPSBleHBlY3RlZC5yb3dDb3VudDtcbiAgY29uc3QgYWN0dWFsUm93Q291bnQgPSBhY3R1YWwucm93Q291bnQ7XG4gIGV4cGVjdChhY3R1YWxSb3dDb3VudCwgZXhwZWN0ZWRSb3dDb3VudCwgYCR7ZXJyb3IgPz8gJyd9LCByb3cgY291bnRgKTtcblxuICBmb3IgKGNvbnN0IGNvbHVtbiBvZiBleHBlY3RlZC5jb2x1bW5zKSB7XG4gICAgY29uc3QgYWN0dWFsQ29sdW1uID0gYWN0dWFsLmNvbHVtbnMuYnlOYW1lKGNvbHVtbi5uYW1lKTtcbiAgICBpZiAoYWN0dWFsQ29sdW1uID09IG51bGwpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvbHVtbiAke2NvbHVtbi5uYW1lfSBub3QgZm91bmRgKTtcbiAgICBpZiAoYWN0dWFsQ29sdW1uLnR5cGUgIT0gY29sdW1uLnR5cGUpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvbHVtbiAke2NvbHVtbi5uYW1lfSB0eXBlIGV4cGVjdGVkICR7Y29sdW1uLnR5cGV9IGdvdCAke2FjdHVhbENvbHVtbi50eXBlfWApO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZXhwZWN0ZWRSb3dDb3VudDsgaSsrKSB7XG4gICAgICBjb25zdCB2YWx1ZSA9IGNvbHVtbi5nZXQoaSk7XG4gICAgICBjb25zdCBhY3R1YWxWYWx1ZSA9IGFjdHVhbENvbHVtbi5nZXQoaSk7XG4gICAgICBpZiAoY29sdW1uLnR5cGUgPT0gREcuVFlQRS5GTE9BVClcbiAgICAgICAgZXhwZWN0RmxvYXQoYWN0dWFsVmFsdWUsIHZhbHVlLCAwLjAwMDEsIGVycm9yKTtcbiAgICAgIGVsc2UgaWYgKGNvbHVtbi50eXBlID09IERHLlRZUEUuREFURV9USU1FKVxuICAgICAgICBleHBlY3QoYWN0dWFsVmFsdWUuaXNTYW1lKHZhbHVlKSwgdHJ1ZSwgZXJyb3IpO1xuICAgICAgZWxzZVxuICAgICAgICBleHBlY3QoYWN0dWFsVmFsdWUsIHZhbHVlLCBlcnJvcik7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBleHBlY3RPYmplY3QoYWN0dWFsOiB7IFtrZXk6IHN0cmluZ106IGFueSB9LCBleHBlY3RlZDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSkge1xuICBmb3IgKGNvbnN0IFtleHBlY3RlZEtleSwgZXhwZWN0ZWRWYWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoZXhwZWN0ZWQpKSB7XG4gICAgaWYgKCFhY3R1YWwuaGFzT3duUHJvcGVydHkoZXhwZWN0ZWRLZXkpKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBwcm9wZXJ0eSBcIiR7ZXhwZWN0ZWRLZXl9XCIgbm90IGZvdW5kYCk7XG5cbiAgICBjb25zdCBhY3R1YWxWYWx1ZSA9IGFjdHVhbFtleHBlY3RlZEtleV07XG4gICAgaWYgKGFjdHVhbFZhbHVlIGluc3RhbmNlb2YgQXJyYXkgJiYgZXhwZWN0ZWRWYWx1ZSBpbnN0YW5jZW9mIEFycmF5KVxuICAgICAgZXhwZWN0QXJyYXkoYWN0dWFsVmFsdWUsIGV4cGVjdGVkVmFsdWUpO1xuICAgIGVsc2UgaWYgKGFjdHVhbFZhbHVlIGluc3RhbmNlb2YgT2JqZWN0ICYmIGV4cGVjdGVkVmFsdWUgaW5zdGFuY2VvZiBPYmplY3QpXG4gICAgICBleHBlY3RPYmplY3QoYWN0dWFsVmFsdWUsIGV4cGVjdGVkVmFsdWUpO1xuICAgIGVsc2UgaWYgKE51bWJlci5pc0Zpbml0ZShhY3R1YWxWYWx1ZSkgJiYgTnVtYmVyLmlzRmluaXRlKGV4cGVjdGVkVmFsdWUpKVxuICAgICAgZXhwZWN0RmxvYXQoYWN0dWFsVmFsdWUsIGV4cGVjdGVkVmFsdWUpO1xuICAgIGVsc2UgaWYgKGFjdHVhbFZhbHVlICE9IGV4cGVjdGVkVmFsdWUpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkICgke2V4cGVjdGVkVmFsdWV9KSBmb3Iga2V5ICcke2V4cGVjdGVkS2V5fScsIGdvdCAoJHthY3R1YWxWYWx1ZX0pYCk7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGV4cGVjdEFycmF5KGFjdHVhbDogQXJyYXlMaWtlPGFueT4sIGV4cGVjdGVkOiBBcnJheUxpa2U8YW55Pikge1xuICBjb25zdCBhY3R1YWxMZW5ndGggPSBhY3R1YWwubGVuZ3RoO1xuICBjb25zdCBleHBlY3RlZExlbmd0aCA9IGV4cGVjdGVkLmxlbmd0aDtcblxuICBpZiAoYWN0dWFsTGVuZ3RoICE9IGV4cGVjdGVkTGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBcnJheXMgYXJlIG9mIGRpZmZlcmVudCBsZW5ndGg6IGFjdHVhbCBhcnJheSBsZW5ndGggaXMgJHthY3R1YWxMZW5ndGh9IGAgK1xuICAgICAgYGFuZCBleHBlY3RlZCBhcnJheSBsZW5ndGggaXMgJHtleHBlY3RlZExlbmd0aH1gKTtcbiAgfVxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYWN0dWFsTGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoYWN0dWFsW2ldIGluc3RhbmNlb2YgQXJyYXkgJiYgZXhwZWN0ZWRbaV0gaW5zdGFuY2VvZiBBcnJheSlcbiAgICAgIGV4cGVjdEFycmF5KGFjdHVhbFtpXSwgZXhwZWN0ZWRbaV0pO1xuICAgIGVsc2UgaWYgKGFjdHVhbFtpXSBpbnN0YW5jZW9mIE9iamVjdCAmJiBleHBlY3RlZFtpXSBpbnN0YW5jZW9mIE9iamVjdClcbiAgICAgIGV4cGVjdE9iamVjdChhY3R1YWxbaV0sIGV4cGVjdGVkW2ldKTtcbiAgICBlbHNlIGlmIChhY3R1YWxbaV0gIT0gZXhwZWN0ZWRbaV0pXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkICR7ZXhwZWN0ZWRbaV19IGF0IHBvc2l0aW9uICR7aX0sIGdvdCAke2FjdHVhbFtpXX1gKTtcbiAgfVxufVxuXG4vKiBEZWZpbmVzIGEgdGVzdCBzdWl0ZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjYXRlZ29yeShjYXRlZ29yeTogc3RyaW5nLCB0ZXN0c186ICgpID0+IHZvaWQsIG9wdGlvbnM/OiBDYXRlZ29yeU9wdGlvbnMpOiB2b2lkIHtcbiAgY3VycmVudENhdGVnb3J5ID0gY2F0ZWdvcnk7XG4gIHRlc3RzXygpO1xuICBpZiAodGVzdHNbY3VycmVudENhdGVnb3J5XSkge1xuICAgIHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0uY2xlYXIgPSBvcHRpb25zPy5jbGVhciA/PyB0cnVlO1xuICAgIHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0udGltZW91dCA9IG9wdGlvbnM/LnRpbWVvdXQ7XG4gICAgdGVzdHNbY3VycmVudENhdGVnb3J5XS5iZW5jaG1hcmtzID0gb3B0aW9ucz8uYmVuY2htYXJrcztcbiAgICB0ZXN0c1tjdXJyZW50Q2F0ZWdvcnldLnN0cmVzc1Rlc3RzID0gb3B0aW9ucz8uc3RyZXNzVGVzdHM7XG4gICAgdGVzdHNbY3VycmVudENhdGVnb3J5XS5vd25lciA9IG9wdGlvbnM/Lm93bmVyO1xuICB9XG59XG5cbi8qIERlZmluZXMgYSBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBiZWZvcmUgdGhlIHRlc3RzIGluIHRoaXMgY2F0ZWdvcnkgYXJlIGV4ZWN1dGVkLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJlZm9yZShiZWZvcmU6ICgpID0+IFByb21pc2U8dm9pZD4pOiB2b2lkIHtcbiAgaWYgKHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0gPT0gdW5kZWZpbmVkKVxuICAgIHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0gPSB7fTtcbiAgdGVzdHNbY3VycmVudENhdGVnb3J5XS5iZWZvcmUgPSBiZWZvcmU7XG59XG5cbi8qIERlZmluZXMgYSBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBhZnRlciB0aGUgdGVzdHMgaW4gdGhpcyBjYXRlZ29yeSBhcmUgZXhlY3V0ZWQuICovXG5leHBvcnQgZnVuY3Rpb24gYWZ0ZXIoYWZ0ZXI6ICgpID0+IFByb21pc2U8dm9pZD4pOiB2b2lkIHtcbiAgaWYgKHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0gPT0gdW5kZWZpbmVkKVxuICAgIHRlc3RzW2N1cnJlbnRDYXRlZ29yeV0gPSB7fTtcbiAgdGVzdHNbY3VycmVudENhdGVnb3J5XS5hZnRlciA9IGFmdGVyO1xufVxuXG5mdW5jdGlvbiBhZGROYW1lc3BhY2Uoczogc3RyaW5nLCBmOiBfREcuRnVuYyk6IHN0cmluZyB7XG4gIHJldHVybiBzLnJlcGxhY2UobmV3IFJlZ0V4cChmLm5hbWUsICdnaScpLCBmLm5xTmFtZSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbml0QXV0b1Rlc3RzKHBhY2thZ2VfOiBfREcuUGFja2FnZSwgbW9kdWxlPzogYW55KSB7XG4gIGNvbnN0IHBhY2thZ2VJZCA9IHBhY2thZ2VfLmlkO1xuICBpZiAod2FzUmVnaXN0ZXJlZFtwYWNrYWdlSWRdKSByZXR1cm47XG4gIGNvbnN0IG1vZHVsZVRlc3RzID0gbW9kdWxlID8gbW9kdWxlLnRlc3RzIDogdGVzdHM7XG4gIGlmIChwYWNrYWdlXy5uYW1lID09PSAnRGV2VG9vbHMnIHx8ICghIW1vZHVsZSAmJiBtb2R1bGUuX3BhY2thZ2UubmFtZSA9PT0gJ0RldlRvb2xzJykpIHtcbiAgICBmb3IgKGNvbnN0IGYgb2YgKDxhbnk+d2luZG93KS5kYXJ0VGVzdHMpIHtcbiAgICAgIGNvbnN0IGFyciA9IGYubmFtZS5zcGxpdCgvXFxzKlxcfFxccyohL2cpO1xuICAgICAgbGV0IG5hbWUgPSBhcnIucG9wKCkgPz8gZi5uYW1lO1xuICAgICAgbGV0IGNhdCA9IGFyci5sZW5ndGggPyBjb3JlQ2F0TmFtZSArICc6ICcgKyBhcnIuam9pbignOiAnKSA6IGNvcmVDYXROYW1lO1xuICAgICAgbGV0IGZ1bGxOYW1lOiBzdHJpbmdbXSA9IG5hbWUuc3BsaXQoJyB8ICcpO1xuICAgICAgbmFtZSA9IGZ1bGxOYW1lW2Z1bGxOYW1lLmxlbmd0aCAtIDFdO1xuICAgICAgZnVsbE5hbWUudW5zaGlmdChjYXQpO1xuICAgICAgZnVsbE5hbWUucG9wKCk7XG4gICAgICBjYXQgPSBmdWxsTmFtZS5qb2luKCc6ICcpO1xuICAgICAgaWYgKG1vZHVsZVRlc3RzW2NhdF0gPT09IHVuZGVmaW5lZClcbiAgICAgICAgbW9kdWxlVGVzdHNbY2F0XSA9IHsgdGVzdHM6IFtdLCBjbGVhcjogdHJ1ZSB9O1xuICAgICAgbW9kdWxlVGVzdHNbY2F0XS50ZXN0cy5wdXNoKG5ldyBUZXN0KGNhdCwgbmFtZSwgZi50ZXN0LCB7IGlzQWdncmVnYXRlZDogZmFsc2UsIHRpbWVvdXQ6IGYub3B0aW9ucz8udGltZW91dCA/PyBTVEFOREFSVF9USU1FT1VULCBza2lwUmVhc29uOiBmLm9wdGlvbnM/LnNraXBSZWFzb24sIG93bmVyOiBmLm9wdGlvbnM/Lm93bmVyLCBiZW5jaG1hcms6IGYub3B0aW9ucz8uYmVuY2htYXJrID8/IGZhbHNlIH0pKTtcbiAgICB9XG4gIH1cbiAgY29uc3QgbW9kdWxlQXV0b1Rlc3RzID0gW107XG4gIGNvbnN0IG1vZHVsZURlbW8gPSBbXTtcbiAgY29uc3QgbW9kdWxlRGV0ZWN0b3JzID0gW107XG4gIGNvbnN0IHBhY2tGdW5jdGlvbnMgPSBhd2FpdCBncm9rLmRhcGkuZnVuY3Rpb25zLmZpbHRlcihgcGFja2FnZS5pZCA9IFwiJHtwYWNrYWdlSWR9XCJgKS5saXN0KCk7XG4gIGNvbnN0IHJlZyA9IG5ldyBSZWdFeHAoL3NraXA6XFxzKihbXixcXHNdKyl8d2FpdDpcXHMqKFxcZCspfGNhdDpcXHMqKFteLFxcc10rKXx0aW1lb3V0OlxccyooXFxkKykvZyk7XG4gIGZvciAoY29uc3QgZiBvZiBwYWNrRnVuY3Rpb25zKSB7XG4gICAgY29uc3QgdGVzdHMgPSBmLm9wdGlvbnNbJ3Rlc3QnXTtcbiAgICBjb25zdCBkZW1vID0gZi5vcHRpb25zWydkZW1vUGF0aCddO1xuICAgIGlmICgodGVzdHMgJiYgQXJyYXkuaXNBcnJheSh0ZXN0cykgJiYgdGVzdHMubGVuZ3RoKSkge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0ZXN0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCByZXMgPSAodGVzdHNbaV0gYXMgc3RyaW5nKS5tYXRjaEFsbChyZWcpO1xuICAgICAgICBjb25zdCBtYXA6IHsgc2tpcD86IHN0cmluZywgd2FpdD86IG51bWJlciwgY2F0Pzogc3RyaW5nLCB0aW1lb3V0PzogbnVtYmVyLCBiZW5jaG1hcmtUaW1lb3V0PzogbnVtYmVyIH0gPSB7fTtcbiAgICAgICAgQXJyYXkuZnJvbShyZXMpLmZvckVhY2goKGFycikgPT4ge1xuICAgICAgICAgIGlmIChhcnJbMF0uc3RhcnRzV2l0aCgnc2tpcCcpKSBtYXBbJ3NraXAnXSA9IGFyclsxXTtcbiAgICAgICAgICBlbHNlIGlmIChhcnJbMF0uc3RhcnRzV2l0aCgnd2FpdCcpKSBtYXBbJ3dhaXQnXSA9IHBhcnNlSW50KGFyclsyXSk7XG4gICAgICAgICAgZWxzZSBpZiAoYXJyWzBdLnN0YXJ0c1dpdGgoJ2NhdCcpKSBtYXBbJ2NhdCddID0gYXJyWzNdO1xuICAgICAgICAgIGVsc2UgaWYgKGFyclswXS5zdGFydHNXaXRoKCd0aW1lb3V0JykpIG1hcFsndGltZW91dCddID0gcGFyc2VJbnQoYXJyWzRdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHRlc3QgPSBuZXcgVGVzdChtYXAuY2F0ID8/IGF1dG9UZXN0c0NhdE5hbWUsIHRlc3RzLmxlbmd0aCA9PT0gMSA/IGYubmFtZSA6IGAke2YubmFtZX0gJHtpICsgMX1gLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgZ3Jvay5mdW5jdGlvbnMuZXZhbChhZGROYW1lc3BhY2UodGVzdHNbaV0sIGYpKTtcbiAgICAgICAgICBpZiAobWFwLndhaXQpIGF3YWl0IGRlbGF5KG1hcC53YWl0KTtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdGhyb3ctbGl0ZXJhbFxuICAgICAgICAgIGlmICh0eXBlb2YgcmVzID09PSAnYm9vbGVhbicgJiYgIXJlcykgdGhyb3cgYEZhaWxlZDogJHt0ZXN0c1tpXX0sIGV4cGVjdGVkIHRydWUsIGdvdCAke3Jlc31gO1xuICAgICAgICB9LCB7IHNraXBSZWFzb246IG1hcC5za2lwLCB0aW1lb3V0OiBERy5UZXN0LmlzSW5CZW5jaG1hcmsgPyBtYXAuYmVuY2htYXJrVGltZW91dCA/PyBCRU5DSE1BUktfVElNRU9VVCA6IG1hcC50aW1lb3V0ID8/IFNUQU5EQVJUX1RJTUVPVVQgfSk7XG4gICAgICAgIGlmIChtYXAuY2F0KSB7XG4gICAgICAgICAgY29uc3QgY2F0OiBzdHJpbmcgPSBtYXAuY2F0O1xuICAgICAgICAgIGlmIChtb2R1bGVUZXN0c1tjYXRdID09PSB1bmRlZmluZWQpXG4gICAgICAgICAgICBtb2R1bGVUZXN0c1tjYXRdID0geyB0ZXN0czogW10sIGNsZWFyOiB0cnVlIH07XG5cbiAgICAgICAgICAvLyBvbmx5IGJlZm9yZS9hZnRlciBjYW4gYmUgZGVmaW5lZCBpbiB0cyBmaWxlcyB0ZXN0cyB1bmRlciB0aGUgY2F0ZWdvcnlcbiAgICAgICAgICBpZiAoIW1vZHVsZVRlc3RzW2NhdF0udGVzdHMpXG4gICAgICAgICAgICBtb2R1bGVUZXN0c1tjYXRdLnRlc3RzID0gW107XG4gICAgICAgICAgbW9kdWxlVGVzdHNbY2F0XS50ZXN0cy5wdXNoKHRlc3QpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAgICBtb2R1bGVBdXRvVGVzdHMucHVzaCh0ZXN0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGRlbW8pIHtcbiAgICAgIGNvbnN0IHdhaXQgPSBmLm9wdGlvbnNbJ2RlbW9XYWl0J10gPyBwYXJzZUludChmLm9wdGlvbnNbJ2RlbW9XYWl0J10pIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3QgdGVzdCA9IG5ldyBUZXN0KGRlbW9DYXROYW1lLCBmLmZyaWVuZGx5TmFtZSwgYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCBkZWxheSgzMDApO1xuICAgICAgICBncm9rLnNoZWxsLmNsZWFyTGFzdEVycm9yKCk7XG4gICAgICAgIGF3YWl0IGYuYXBwbHkoKTtcbiAgICAgICAgYXdhaXQgZGVsYXkod2FpdCA/IHdhaXQgOiAyMDAwKTtcbiAgICAgICAgY29uc3QgdW5oYW5kbGVkID0gYXdhaXQgZ3Jvay5zaGVsbC5sYXN0RXJyb3I7XG4gICAgICAgIGlmICh1bmhhbmRsZWQpXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHVuaGFuZGxlZCk7XG4gICAgICB9LCB7IHNraXBSZWFzb246IGYub3B0aW9uc1snZGVtb1NraXAnXSB9KTtcbiAgICAgIG1vZHVsZURlbW8ucHVzaCh0ZXN0KTtcbiAgICB9XG4gICAgaWYgKGYuaGFzVGFnKCdzZW1UeXBlRGV0ZWN0b3InKSkge1xuICAgICAgbGV0IGRldGVjdG9yc1Rlc3REYXRhID0gdGVzdERhdGE7XG4gICAgICBpZiAoZi5vcHRpb25zWyd0ZXN0RGF0YSddKSB7XG4gICAgICAgIGRldGVjdG9yc1Rlc3REYXRhID0gYXdhaXQgZ3Jvay5kYXRhLmZpbGVzLm9wZW5UYWJsZShgU3lzdGVtOkFwcERhdGEvJHtwYWNrYWdlXy5ucU5hbWV9LyR7Zi5vcHRpb25zWyd0ZXN0RGF0YSddfWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0ZXN0ID0gbmV3IFRlc3QoZGV0ZWN0b3JzQ2F0TmFtZSwgZi5mcmllbmRseU5hbWUsIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgYXJyID0gW107XG4gICAgICAgIGNvbnNvbGUubG9nKGBTeXN0ZW06QXBwRGF0YS8ke3BhY2thZ2VfLm5xTmFtZX0vJHtmLm9wdGlvbnNbJ3Rlc3REYXRhJ119YCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBjb2wgb2YgZGV0ZWN0b3JzVGVzdERhdGEuY2xvbmUoKS5jb2x1bW5zKSB7XG4gICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgZi5hcHBseShbY29sXSk7XG4gICAgICAgICAgYXJyLnB1c2gocmVzIHx8IGNvbC5zZW1UeXBlKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCByZXNBcnIgPSBhcnIuZmlsdGVyKChpKSA9PiBpKTtcbiAgICAgICAgZXhwZWN0KHJlc0Fyci5sZW5ndGgsIDEpO1xuXG4gICAgICAgIGlmIChmLm9wdGlvbnNbJ3Rlc3REYXRhQ29sdW1uTmFtZSddKVxuICAgICAgICAgIGV4cGVjdChyZXNBcnJbMF0sIGYub3B0aW9uc1sndGVzdERhdGFDb2x1bW5OYW1lJ10pO1xuXG4gICAgICB9LCB7IHNraXBSZWFzb246IGYub3B0aW9uc1snc2tpcFRlc3QnXSB9KTtcbiAgICAgIG1vZHVsZURldGVjdG9ycy5wdXNoKHRlc3QpO1xuICAgIH1cbiAgfVxuICB3YXNSZWdpc3RlcmVkW3BhY2thZ2VJZF0gPSB0cnVlO1xuICBpZiAobW9kdWxlQXV0b1Rlc3RzLmxlbmd0aCA+IDApXG4gICAgbW9kdWxlVGVzdHNbYXV0b1Rlc3RzQ2F0TmFtZV0gPSB7IHRlc3RzOiBtb2R1bGVBdXRvVGVzdHMsIGNsZWFyOiB0cnVlIH07XG4gIGlmIChtb2R1bGVEZW1vLmxlbmd0aCA+IDApXG4gICAgbW9kdWxlVGVzdHNbZGVtb0NhdE5hbWVdID0geyB0ZXN0czogbW9kdWxlRGVtbywgY2xlYXI6IHRydWUgfTtcbiAgaWYgKG1vZHVsZURldGVjdG9ycy5sZW5ndGggPiAwKVxuICAgIG1vZHVsZVRlc3RzW2RldGVjdG9yc0NhdE5hbWVdID0geyB0ZXN0czogbW9kdWxlRGV0ZWN0b3JzLCBjbGVhcjogZmFsc2UgfTtcbn1cblxuZnVuY3Rpb24gcmVkZWZpbmVDb25zb2xlKCk6IGFueVtdIHtcbiAgY29uc3QgbG9nczogYW55W10gPSBbXTtcbiAgY29uc29sZS5sb2cgPSAoLi4uYXJncykgPT4ge1xuICAgIGxvZ3MucHVzaCguLi5hcmdzKTtcbiAgICBzdGRMb2coLi4uYXJncyk7XG4gIH07XG4gIGNvbnNvbGUuaW5mbyA9ICguLi5hcmdzKSA9PiB7XG4gICAgbG9ncy5wdXNoKC4uLmFyZ3MpO1xuICAgIHN0ZEluZm8oLi4uYXJncyk7XG4gIH07XG4gIGNvbnNvbGUud2FybiA9ICguLi5hcmdzKSA9PiB7XG4gICAgbG9ncy5wdXNoKC4uLmFyZ3MpO1xuICAgIHN0ZFdhcm4oLi4uYXJncyk7XG4gIH07XG4gIGNvbnNvbGUuZXJyb3IgPSAoLi4uYXJncykgPT4ge1xuICAgIGxvZ3MucHVzaCguLi5hcmdzKTtcbiAgICBzdGRFcnJvciguLi5hcmdzKTtcbiAgfTtcbiAgcmV0dXJuIGxvZ3M7XG59XG5cbmZ1bmN0aW9uIHJlc2V0Q29uc29sZSgpOiB2b2lkIHtcbiAgY29uc29sZS5sb2cgPSBzdGRMb2c7XG4gIGNvbnNvbGUuaW5mbyA9IHN0ZEluZm87XG4gIGNvbnNvbGUud2FybiA9IHN0ZFdhcm47XG4gIGNvbnNvbGUuZXJyb3IgPSBzdGRFcnJvcjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1blRlc3RzKG9wdGlvbnM/OiBUZXN0RXhlY3V0aW9uT3B0aW9ucykgOiBQcm9taXNlPFRlc3RSZXN1bHRFeHRlbmRlZFtdPntcblxuICBjb25zdCBwYWNrYWdlXzogX0RHLlBhY2thZ2UgPSBvcHRpb25zPy5ub2RlT3B0aW9ucyA/IG9wdGlvbnMubm9kZU9wdGlvbnMucGFja2FnZSA6IGdyb2suZnVuY3Rpb25zLmdldEN1cnJlbnRDYWxsKCkuZnVuYy5wYWNrYWdlO1xuICBpZiAoIXBhY2thZ2VfKVxuICAgIHRocm93IG5ldyBFcnJvcignQ2FuXFwndCBydW4gdGVzdHMgb3V0c2lkZSBvZiB0aGUgcGFja2FnZScpO1xuICBjb25zdCBtYXRjaCA9IHBhY2thZ2VfLnBhY2thZ2VPd25lcj8ubWF0Y2goLzwoW14+XSopPi8pO1xuICBjb25zdCBwYWNrYWdlT3duZXIgPSBtYXRjaCA/IG1hdGNoWzFdIDogJyc7XG4gIGlmIChwYWNrYWdlXyAhPSB1bmRlZmluZWQpXG4gICAgYXdhaXQgaW5pdEF1dG9UZXN0cyhwYWNrYWdlXyk7XG4gIGNvbnN0IHJlc3VsdHM6VGVzdFJlc3VsdEV4dGVuZGVkW10gPSBbXTtcbiAgY29uc29sZS5sb2coYFJ1bm5pbmcgdGVzdHMuLi5gKTtcbiAgY29uc29sZS5sb2cob3B0aW9ucyk7XG4gIG9wdGlvbnMgPz89IHt9O1xuICBvcHRpb25zIS50ZXN0Q29udGV4dCA/Pz0gbmV3IFRlc3RDb250ZXh0KCk7XG4gIGdyb2suc2hlbGwuY2xlYXJMYXN0RXJyb3IoKTtcbiAgY29uc3QgbG9ncyA9IHJlZGVmaW5lQ29uc29sZSgpO1xuXG4gIGF3YWl0IGludm9rZVRlc3RzKHRlc3RzLCBvcHRpb25zKTtcblxuICBmb3IgKGxldCByIG9mIHJlc3VsdHMpIHtcbiAgICByLnJlc3VsdCA9IHIucmVzdWx0LnRvU3RyaW5nKCkucmVwbGFjZSgvXCIvZywgJ1xcJycpO1xuICAgIGlmIChyLmxvZ3MgIT0gdW5kZWZpbmVkKVxuICAgICAgci5sb2dzID0gci5sb2dzIS50b1N0cmluZygpLnJlcGxhY2UoL1wiL2csICdcXCcnKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cztcblxuICBhc3luYyBmdW5jdGlvbiBpbnZva2VDYXRlZ29yeU1ldGhvZChtZXRob2Q6ICgoKSA9PiBQcm9taXNlPHZvaWQ+KSB8IHVuZGVmaW5lZCwgY2F0ZWdvcnk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gICAgbGV0IGludm9rYXRpb25SZXN1bHQgPSB1bmRlZmluZWQ7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChtZXRob2QgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhd2FpdCB0aW1lb3V0KGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBtZXRob2QoKTtcbiAgICAgICAgfSwgMTAwMDAwLCBgYmVmb3JlICR7Y2F0ZWdvcnl9OiB0aW1lb3V0IGVycm9yYCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoeDogYW55KSB7XG4gICAgICBpbnZva2F0aW9uUmVzdWx0ID0gYXdhaXQgZ2V0UmVzdWx0KHgpO1xuICAgIH1cbiAgICByZXR1cm4gaW52b2thdGlvblJlc3VsdFxuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gaW52b2tlVGVzdHNJbkNhdGVnb3J5KGNhdGVnb3J5OiBDYXRlZ29yeSwgb3B0aW9uczogVGVzdEV4ZWN1dGlvbk9wdGlvbnMsIGlzVGFyZ2V0Q2F0ZWdvcnk6IGJvb2xlYW4pOiBQcm9taXNlPFRlc3RSZXN1bHRFeHRlbmRlZFtdPiB7XG4gICAgbGV0IHQgPSBjYXRlZ29yeS50ZXN0cyA/PyBbXTtcbiAgICBjb25zdCByZXMgOiBUZXN0UmVzdWx0RXh0ZW5kZWRbXSA9IFtdO1xuICAgIC8vIGxldCBtZW1vcnlVc2FnZUJlZm9yZSA9ICh3aW5kb3c/LnBlcmZvcm1hbmNlIGFzIGFueSk/Lm1lbW9yeT8udXNlZEpTSGVhcFNpemU7XG4gICAgY29uc3Qgd2lkZ2V0c0JlZm9yZSA9IGdldFdpZGdldHNDb3VudFNhZmUoKTtcblxuICAgIGlmIChjYXRlZ29yeS5jbGVhcikge1xuICAgICAgICBsZXQgc2tpcHBpbmdUZXN0cyA9IGlzVGFyZ2V0Q2F0ZWdvcnkgJiYgb3B0aW9ucy5za2lwVG9UZXN0ICE9IHVuZGVmaW5lZDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5sZW5ndGg7IGkrKykge1xuXG4gICAgICAgIGlmICh0W2ldLm9wdGlvbnMpIHtcbiAgICAgICAgICBpZiAodFtpXS5vcHRpb25zPy5iZW5jaG1hcmsgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgaWYgKCF0W2ldLm9wdGlvbnMpXG4gICAgICAgICAgICAgIHRbaV0ub3B0aW9ucyA9IHt9XG4gICAgICAgICAgICB0W2ldLm9wdGlvbnMhLmJlbmNobWFyayA9IGNhdGVnb3J5LmJlbmNobWFya3MgPz8gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCB0ZXN0ID0gdFtpXTtcbiAgICAgICAgaWYgKG9wdGlvbnMudGVzdClcbiAgICAgICAgICBpZiAob3B0aW9ucy50ZXN0LnRvTG93ZXJDYXNlKCkgIT09IHRlc3QubmFtZS50b0xvd2VyQ2FzZSgpKVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIGlmIChza2lwcGluZ1Rlc3RzKSB7XG4gICAgICAgICAgaWYgKG9wdGlvbnM/LnNraXBUb1Rlc3QgIT0gdW5kZWZpbmVkICYmIHRlc3QubmFtZS50b0xvd2VyQ2FzZSgpLnRyaW0oKSA9PT0gb3B0aW9ucz8uc2tpcFRvVGVzdC50b0xvd2VyQ2FzZSgpLnRyaW0oKSkge1xuICAgICAgICAgICAgLy8gRm91bmQgdGhlIHRhcmdldCB0ZXN0LCBzdG9wIHNraXBwaW5nIGFmdGVyIHRoaXMgb25lXG4gICAgICAgICAgICBza2lwcGluZ1Rlc3RzID0gZmFsc2U7XG4gICAgICAgICAgfSBlbHNlXG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRlc3Q/Lm9wdGlvbnMpIHtcbiAgICAgICAgICB0ZXN0Lm9wdGlvbnMub3duZXIgPSB0W2ldLm9wdGlvbnM/Lm93bmVyID8/IGNhdGVnb3J5Py5vd25lciA/PyBwYWNrYWdlT3duZXIgPz8gJyc7XG4gICAgICAgIH1cbiAgICAgICAgLy8gbGV0IGlzR0JFbmFibGUgPSAod2luZG93IGFzIGFueSkuZ2MgJiYgdGVzdC5vcHRpb25zPy5za2lwUmVhc29uID09IHVuZGVmaW5lZDtcbiAgICAgICAgLy8gY29uc29sZS5sb2coYCoqKioqKioqJHtpc0dCRW5hYmxlfWApO1xuICAgICAgICAvLyBpZiAoaXNHQkVuYWJsZSlcbiAgICAgICAgLy8gICBhd2FpdCAod2luZG93IGFzIGFueSkuZ2MoKTtcbiAgICAgICAgLy8gbWVtb3J5VXNhZ2VCZWZvcmUgPSAod2luZG93Py5wZXJmb3JtYW5jZSBhcyBhbnkpPy5tZW1vcnk/LnVzZWRKU0hlYXBTaXplO1xuICAgICAgICBsZXQgdGVzdFJ1biA9IGF3YWl0IGV4ZWNUZXN0KFxuICAgICAgICAgICAgdGVzdCxcbiAgICAgICAgICAgIG9wdGlvbnM/LnRlc3QsXG4gICAgICAgICAgICBsb2dzLCBERy5UZXN0LmlzSW5CZW5jaG1hcmsgPyB0W2ldLm9wdGlvbnM/LmJlbmNobWFya1RpbWVvdXQgPz8gQkVOQ0hNQVJLX1RJTUVPVVQgOiB0W2ldLm9wdGlvbnM/LnRpbWVvdXQgPz8gU1RBTkRBUlRfVElNRU9VVCxcbiAgICAgICAgICAgIHBhY2thZ2VfLm5hbWUsXG4gICAgICAgICAgICBvcHRpb25zLnZlcmJvc2VcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBpZiAoaXNHQkVuYWJsZSlcbiAgICAgICAgLy8gICBhd2FpdCAod2luZG93IGFzIGFueSkuZ2MoKTtcbiAgICAgICAgaWYgKHRlc3RSdW4pIHtcbiAgICAgICAgICByZXMucHVzaCh7IC4uLnRlc3RSdW4sICB3aWRnZXRzRGlmZmVyZW5jZTogZ2V0V2lkZ2V0c0NvdW50U2FmZSgpIC0gd2lkZ2V0c0JlZm9yZSB9KTtcbiAgICAgICAgICAvLyBSZXR1cm4gZWFybHkgaWYgcmV0dXJuT25GYWlsIGlzIHNldCBhbmQgdGVzdCBmYWlsZWQgKGJ1dCBpZ25vcmUgZmFpbHVyZSBmb3IgdGhlIHNraXBUb1Rlc3QgdGVzdCBpdHNlbGYpXG4gICAgICAgICAgaWYgKG9wdGlvbnMucmV0dXJuT25GYWlsICYmIG9wdGlvbnMuc2tpcFRvVGVzdCAhPT0gdGVzdC5uYW1lICYmICF0ZXN0UnVuLnN1Y2Nlc3MgJiYgIXRlc3RSdW4uc2tpcHBlZClcbiAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVzLnB1c2goeyAuLi50ZXN0UnVuLCBtZW1vcnlEZWx0YTogKHdpbmRvdz8ucGVyZm9ybWFuY2UgYXMgYW55KT8ubWVtb3J5Py51c2VkSlNIZWFwU2l6ZSAtIG1lbW9yeVVzYWdlQmVmb3JlLCB3aWRnZXRzRGVsdGE6IGdldFdpZGdldHNDb3VudFNhZmUoKSAtIHdpZGdldHNCZWZvcmUgfSk7XG5cbiAgICAgICAgaWYgKCFvcHRpb25zLm5vZGVPcHRpb25zKSB7XG4gICAgICAgICAgZ3Jvay5zaGVsbC5jbG9zZUFsbCgpO1xuICAgICAgICAgIERHLkJhbGxvb24uY2xvc2VBbGwoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgc2tpcHBpbmdUZXN0cyA9IGlzVGFyZ2V0Q2F0ZWdvcnkgJiYgb3B0aW9ucy5za2lwVG9UZXN0ICE9IHVuZGVmaW5lZDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdC5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgdGVzdCA9IHRbaV07XG4gICAgICAgIGlmIChvcHRpb25zLnRlc3QpXG4gICAgICAgICAgaWYgKG9wdGlvbnMudGVzdC50b0xvd2VyQ2FzZSgpICE9PSB0ZXN0Lm5hbWUudG9Mb3dlckNhc2UoKSlcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICBpZiAoc2tpcHBpbmdUZXN0cykge1xuICAgICAgICAgIGlmIChvcHRpb25zPy5za2lwVG9UZXN0ICE9IHVuZGVmaW5lZCAmJiB0ZXN0Lm5hbWUudG9Mb3dlckNhc2UoKS50cmltKCkgPT09IG9wdGlvbnM/LnNraXBUb1Rlc3QudG9Mb3dlckNhc2UoKS50cmltKCkpIHtcbiAgICAgICAgICAgIC8vIEZvdW5kIHRoZSB0YXJnZXQgdGVzdCwgc3RvcCBza2lwcGluZyBhZnRlciB0aGlzIG9uZVxuICAgICAgICAgICAgc2tpcHBpbmdUZXN0cyA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb250aW51ZTsgIC8vIFNraXAgdGhpcyB0ZXN0IChpbmNsdWRpbmcgdGhlIHRhcmdldClcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0ZXN0Py5vcHRpb25zKSB7XG4gICAgICAgICAgdGVzdC5vcHRpb25zLm93bmVyID0gdFtpXS5vcHRpb25zPy5vd25lciA/PyBjYXRlZ29yeT8ub3duZXIgPz8gcGFja2FnZU93bmVyID8/ICcnO1xuICAgICAgICB9XG4gICAgICAgIC8vIGxldCBpc0dCRW5hYmxlID0gKHdpbmRvdyBhcyBhbnkpLmdjICYmIHRlc3Qub3B0aW9ucz8uc2tpcFJlYXNvbiA9PSB1bmRlZmluZWQ7XG4gICAgICAgIC8vIGNvbnNvbGUubG9nKGAqKioqKioqKiR7aXNHQkVuYWJsZX1gKTtcbiAgICAgICAgLy8gaWYgKGlzR0JFbmFibGUpXG4gICAgICAgIC8vICAgYXdhaXQgKHdpbmRvdyBhcyBhbnkpLmdjKCk7XG4gICAgICAgIC8vIG1lbW9yeVVzYWdlQmVmb3JlID0gKHdpbmRvdz8ucGVyZm9ybWFuY2UgYXMgYW55KT8ubWVtb3J5Py51c2VkSlNIZWFwU2l6ZTtcbiAgICAgICAgbGV0IHRlc3RSdW4gPSBhd2FpdCBleGVjVGVzdChcbiAgICAgICAgICAgIHRlc3QsXG4gICAgICAgICAgICBvcHRpb25zPy50ZXN0LFxuICAgICAgICAgICAgbG9ncyxcbiAgICAgICAgICAgIERHLlRlc3QuaXNJbkJlbmNobWFyayA/IHRbaV0ub3B0aW9ucz8uYmVuY2htYXJrVGltZW91dCA/PyBCRU5DSE1BUktfVElNRU9VVCA6IHRbaV0ub3B0aW9ucz8udGltZW91dCxcbiAgICAgICAgICAgIHBhY2thZ2VfLm5hbWUsXG4gICAgICAgICAgICBvcHRpb25zLnZlcmJvc2VcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBpZiAoaXNHQkVuYWJsZSlcbiAgICAgICAgLy8gICBhd2FpdCAod2luZG93IGFzIGFueSkuZ2MoKTtcblxuICAgICAgICBpZiAodGVzdFJ1bikge1xuICAgICAgICAgIHJlcy5wdXNoKHsgLi4udGVzdFJ1biwgd2lkZ2V0c0RpZmZlcmVuY2U6IGdldFdpZGdldHNDb3VudFNhZmUoKSAtIHdpZGdldHNCZWZvcmUgfSk7XG4gICAgICAgICAgLy8gUmV0dXJuIGVhcmx5IGlmIHJldHVybk9uRmFpbCBpcyBzZXQgYW5kIHRlc3QgZmFpbGVkIChidXQgaWdub3JlIGZhaWx1cmUgZm9yIHRoZSBza2lwVG9UZXN0IHRlc3QgaXRzZWxmKVxuICAgICAgICAgIGlmIChvcHRpb25zLnJldHVybk9uRmFpbCAmJiBvcHRpb25zLnNraXBUb1Rlc3QgIT09IHRlc3QubmFtZSAmJiAhdGVzdFJ1bi5zdWNjZXNzICYmICF0ZXN0UnVuLnNraXBwZWQpXG4gICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICB9XG4gICAgICAgIC8vIHJlcy5wdXNoKHsgLi4udGVzdFJ1biwgbWVtb3J5RGVsdGE6ICh3aW5kb3c/LnBlcmZvcm1hbmNlIGFzIGFueSk/Lm1lbW9yeT8udXNlZEpTSGVhcFNpemUgLSBtZW1vcnlVc2FnZUJlZm9yZSwgd2lkZ2V0c0RpZmZlcmVuY2U6IGdldFdpZGdldHNDb3VudFNhZmUoKSAtIHdpZGdldHNCZWZvcmUgfSk7XG5cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbiAgfVxuXG4gIGZ1bmN0aW9uIGdldFdpZGdldHNDb3VudFNhZmUoKSB7XG4gICAgaWYgKHR5cGVvZiBwcm9jZXNzICE9PSAndW5kZWZpbmVkJylcbiAgICAgIHJldHVybiAwO1xuICAgIGxldCBsZW5ndGggPSAtMTtcbiAgICB0cnkge1xuICAgICAgbGVuZ3RoID0gREcuV2lkZ2V0LmdldEFsbCgpLmxlbmd0aDtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUud2FybihlLm1lc3NhZ2UgPz8gZSk7XG4gICAgfVxuICAgIHJldHVybiBsZW5ndGg7XG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBpbnZva2VUZXN0cyhjYXRlZ29yaWVzVG9JbnZva2U6IHsgW2tleTogc3RyaW5nXTogQ2F0ZWdvcnkgfSwgb3B0aW9uczogVGVzdEV4ZWN1dGlvbk9wdGlvbnMpIHtcbiAgICB0cnkge1xuICAgICAgbGV0IHNraXBwaW5nQ2F0ZWdvcmllcyA9IG9wdGlvbnM/LnNraXBUb0NhdGVnb3J5ICE9IHVuZGVmaW5lZDtcbiAgICAgIGxldCBpc1RhcmdldENhdGVnb3J5ID0gZmFsc2U7XG4gICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhjYXRlZ29yaWVzVG9JbnZva2UpKSB7XG4gICAgICAgICAgaWYgKG9wdGlvbnMuZXhjbHVkZT8uc29tZSgoYykgPT4ga2V5LnN0YXJ0c1dpdGgoYykpKVxuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICBpZiAob3B0aW9ucz8uY2F0ZWdvcnkgIT0gbnVsbCAmJiAha2V5LnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aChvcHRpb25zPy5jYXRlZ29yeS50b0xvd2VyQ2FzZSgpLnRyaW0oKSkpXG4gICAgICAgICAgICAgIGNvbnRpbnVlO1xuXG4gICAgICAgICAgaWYgKHNraXBwaW5nQ2F0ZWdvcmllcykge1xuICAgICAgICAgICAgICBpZiAoaXNUYXJnZXRDYXRlZ29yeSlcbiAgICAgICAgICAgICAgICAgIHNraXBwaW5nQ2F0ZWdvcmllcyA9IGZhbHNlO1xuICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIGlmIChvcHRpb25zPy5za2lwVG9DYXRlZ29yeSAhPSBudWxsICYmIGtleS50b0xvd2VyQ2FzZSgpLnRyaW0oKSA9PT0gb3B0aW9ucz8uc2tpcFRvQ2F0ZWdvcnkudG9Mb3dlckNhc2UoKS50cmltKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICBpc1RhcmdldENhdGVnb3J5ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gSGF2ZW4ndCBmb3VuZCB0aGUgdGFyZ2V0IGNhdGVnb3J5IHlldCwga2VlcCBza2lwcGluZ1xuICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vQHRzLWlnbm9yZVxuICAgICAgICAgIGNvbnN0IHNraXBwZWQgPSB2YWx1ZS50ZXN0cz8uZXZlcnkoKHQ6IFRlc3QpID0+IHQub3B0aW9ucz8uc2tpcFJlYXNvblxuICAgICAgICAgICAgICB8fCAob3B0aW9ucz8udGVzdCAhPSBudWxsICYmIG9wdGlvbnMudGVzdC50b0xvd2VyQ2FzZSgpICE9PSB0Lm5hbWUudG9Mb3dlckNhc2UoKSkpO1xuXG4gICAgICAgICAgaWYgKCFza2lwcGVkKSB7XG4gICAgICAgICAgICAgIC8vQHRzLWlnbm9yZVxuICAgICAgICAgICAgICBjb25zdCBza2lwcGVkQ291bnQgPSAodmFsdWUudGVzdHMgPz8gW10pLmZpbHRlcigodDogVGVzdCkgPT5cbiAgICAgICAgICAgICAgICB0Lm9wdGlvbnM/LnNraXBSZWFzb24gfHwgKG9wdGlvbnM/LnRlc3QgIT0gbnVsbCAmJiBvcHRpb25zLnRlc3QudG9Mb3dlckNhc2UoKSAhPT0gdC5uYW1lLnRvTG93ZXJDYXNlKCkpXG4gICAgICAgICAgICAgICkubGVuZ3RoO1xuICAgICAgICAgICAgICBzdGRMb2coYFBhY2thZ2UgdGVzdGluZzogU3RhcnRlZCB7eyR7a2V5fX19JHtza2lwcGVkQ291bnQgPiAwID8gYCBza2lwcGVkIHt7JHtza2lwcGVkQ291bnR9fX1gIDogJyd9YCk7XG4gICAgICAgICAgICAgIHZhbHVlLmJlZm9yZVN0YXR1cyA9IGF3YWl0IGludm9rZUNhdGVnb3J5TWV0aG9kKHZhbHVlLmJlZm9yZSwga2V5KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbGV0IHQgPSB2YWx1ZS50ZXN0cyA/PyBbXTtcblxuICAgICAgICAgIGlmIChvcHRpb25zLnN0cmVzc1Rlc3QpIHtcbiAgICAgICAgICAgICAgdCA9IHQuZmlsdGVyKChlKSA9PiBlLm9wdGlvbnM/LnN0cmVzc1Rlc3QpO1xuICAgICAgICAgICAgICB0ID0gc2h1ZmZsZSh0KTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoKG9wdGlvbnMudGFncz8ubGVuZ3RoID8/IDApID4gMCkge1xuICAgICAgICAgICAgICB0ID0gdC5maWx0ZXIoKGUpID0+XG4gICAgICAgICAgICAgICAgICBlLm9wdGlvbnM/LnRhZ3M/LnNvbWUodGFnID0+IChvcHRpb25zPy50YWdzID8/IFtdKS5pbmNsdWRlcyh0YWcpKVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxldCByZXM6IFRlc3RSZXN1bHRFeHRlbmRlZFtdO1xuICAgICAgICAgIGlmICh2YWx1ZS5iZWZvcmVTdGF0dXMpIHtcbiAgICAgICAgICAgICAgcmVzID0gQXJyYXkuZnJvbSh0Lm1hcCgodGVzdEVsZW0pID0+IHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgZGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBrZXksXG4gICAgICAgICAgICAgICAgICAgICAgbmFtZTogdGVzdEVsZW0ubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQ6ICdiZWZvcmUoKSBmYWlsZWQnLFxuICAgICAgICAgICAgICAgICAgICAgIG1zOiAwLFxuICAgICAgICAgICAgICAgICAgICAgIHNraXBwZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgIGxvZ3M6ICcnLFxuICAgICAgICAgICAgICAgICAgICAgIG93bmVyOiBwYWNrYWdlT3duZXIsXG4gICAgICAgICAgICAgICAgICAgICAgcGFja2FnZTogcGFja2FnZV8ubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICB3aWRnZXRzRGlmZmVyZW5jZTogMCxcbiAgICAgICAgICAgICAgICAgICAgICBmbGFraW5nOiBERy5UZXN0LmlzUmVwcm9kdWNpbmdcbiAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgcmVzLmZvckVhY2goYXN5bmMgKHRlc3QpID0+IGF3YWl0IGdyb2suc2hlbGwucmVwb3J0VGVzdCgncGFja2FnZScsIHRlc3QpKTtcbiAgICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgICAgcmVzID0gYXdhaXQgaW52b2tlVGVzdHNJbkNhdGVnb3J5KHZhbHVlLCBvcHRpb25zLCBza2lwcGluZ0NhdGVnb3JpZXMpO1xuICAgICAgICAgIGNvbnN0IGRhdGE6IFRlc3RSZXN1bHRFeHRlbmRlZFtdID0gcmVzLmZpbHRlcigoZCkgPT4gZC5yZXN1bHQgIT0gJ3NraXBwZWQnKTtcblxuICAgICAgICAgIGlmICghc2tpcHBlZClcbiAgICAgICAgICAgICAgdmFsdWUuYWZ0ZXJTdGF0dXMgPSBhd2FpdCBpbnZva2VDYXRlZ29yeU1ldGhvZCh2YWx1ZS5hZnRlciwga2V5KTtcblxuICAgICAgICAgIC8vIENsZWFyIGFmdGVyIGNhdGVnb3J5XG4gICAgICAgICAgLy8gZ3Jvay5zaGVsbC5jbG9zZUFsbCgpO1xuICAgICAgICAgIC8vIERHLkJhbGxvb24uY2xvc2VBbGwoKTtcbiAgICAgICAgICBpZiAodmFsdWUuYWZ0ZXJTdGF0dXMpIHtcbiAgICAgICAgICAgICAgc3RkTG9nKGBQYWNrYWdlIHRlc3Rpbmc6IENhdGVnb3J5IGFmdGVyKCkge3ske2tleX19fSBmYWlsZWRgKTtcbiAgICAgICAgICAgICAgc3RkTG9nKGBQYWNrYWdlIHRlc3Rpbmc6IFJlc3VsdCBmb3Ige3ske2tleX19fSBhZnRlcjogJHt2YWx1ZS5hZnRlclN0YXR1c31gKTtcbiAgICAgICAgICAgICAgZGF0YS5wdXNoKHtcbiAgICAgICAgICAgICAgICAgIGRhdGU6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBrZXksXG4gICAgICAgICAgICAgICAgICBuYW1lOiAnYWZ0ZXInLFxuICAgICAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgICAgICByZXN1bHQ6IHZhbHVlLmFmdGVyU3RhdHVzLFxuICAgICAgICAgICAgICAgICAgbXM6IDAsXG4gICAgICAgICAgICAgICAgICBza2lwcGVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgIGxvZ3M6ICcnLFxuICAgICAgICAgICAgICAgICAgb3duZXI6IHBhY2thZ2VPd25lcixcbiAgICAgICAgICAgICAgICAgIHBhY2thZ2U6IHBhY2thZ2VfLm5hbWUsXG4gICAgICAgICAgICAgICAgICB3aWRnZXRzRGlmZmVyZW5jZTogMCxcbiAgICAgICAgICAgICAgICAgIGZsYWtpbmc6IERHLlRlc3QuaXNSZXByb2R1Y2luZ1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHZhbHVlLmJlZm9yZVN0YXR1cykge1xuICAgICAgICAgICAgICBzdGRMb2coYFBhY2thZ2UgdGVzdGluZzogQ2F0ZWdvcnkgYmVmb3JlKCkge3ske2tleX19fSBmYWlsZWRgKTtcbiAgICAgICAgICAgICAgc3RkTG9nKGBQYWNrYWdlIHRlc3Rpbmc6IFJlc3VsdCBmb3Ige3ske2tleX19fSBiZWZvcmU6ICR7dmFsdWUuYmVmb3JlU3RhdHVzfWApO1xuICAgICAgICAgICAgICBkYXRhLnB1c2goe1xuICAgICAgICAgICAgICAgICAgZGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgICAgICAgICAgY2F0ZWdvcnk6IGtleSxcbiAgICAgICAgICAgICAgICAgIG5hbWU6ICdiZWZvcmUnLFxuICAgICAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgICAgICByZXN1bHQ6IHZhbHVlLmJlZm9yZVN0YXR1cyxcbiAgICAgICAgICAgICAgICAgIG1zOiAwLFxuICAgICAgICAgICAgICAgICAgc2tpcHBlZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICBsb2dzOiAnJyxcbiAgICAgICAgICAgICAgICAgIG93bmVyOiBwYWNrYWdlT3duZXIsXG4gICAgICAgICAgICAgICAgICBwYWNrYWdlOiBwYWNrYWdlXy5uYW1lLFxuICAgICAgICAgICAgICAgICAgd2lkZ2V0c0RpZmZlcmVuY2U6IDAsXG4gICAgICAgICAgICAgICAgICBmbGFraW5nOiBERy5UZXN0LmlzUmVwcm9kdWNpbmdcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJlc3VsdHMucHVzaCguLi5kYXRhKTtcblxuICAgICAgICAgIC8vIElmIHJldHVybk9uRmFpbCBpcyBzZXQgYW5kIGEgdGVzdCBmYWlsZWQgKG90aGVyIHRoYW4gc2tpcFRvVGVzdCksIHN0b3AgcHJvY2Vzc2luZyBtb3JlIGNhdGVnb3JpZXNcbiAgICAgICAgICBpZiAob3B0aW9ucy5yZXR1cm5PbkZhaWwgJiYgZGF0YS5zb21lKChkKSA9PiAhZC5zdWNjZXNzICYmICFkLnNraXBwZWQgJiYgZC5uYW1lICE9PSBvcHRpb25zLnNraXBUb1Rlc3QpKVxuICAgICAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgcmVzZXRDb25zb2xlKCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLnRlc3RDb250ZXh0IS5jYXRjaFVuaGFuZGxlZCAmJiAoIURHLlRlc3QuaXNJbkJlbmNobWFyaykpIHtcbiAgICAgIGF3YWl0IGRlbGF5KDEwMDApO1xuICAgICAgY29uc3QgZXJyb3IgPSBhd2FpdCBncm9rLnNoZWxsLmxhc3RFcnJvcjtcbiAgICAgIGlmIChlcnJvciAhPSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBjb25zdCBwYXJhbXM6IGFueSA9IHtcbiAgICAgICAgICAgICAgbG9nczogJycsXG4gICAgICAgICAgICAgIGRhdGU6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICAgICAgY2F0ZWdvcnk6ICdVbmhhbmRsZWQgZXhjZXB0aW9ucycsXG4gICAgICAgICAgICAgIG5hbWU6ICdFeGNlcHRpb24nLFxuICAgICAgICAgICAgICByZXN1bHQ6IGVycm9yID8/ICcnLFxuICAgICAgICAgICAgICBzdWNjZXNzOiAhZXJyb3IsXG4gICAgICAgICAgICAgIG1zOiAwLFxuICAgICAgICAgICAgICBza2lwcGVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgb3duZXI6IHBhY2thZ2VPd25lciA/PyAnJyxcbiAgICAgICAgICAgICAgJ3BhY2thZ2UnOiBwYWNrYWdlXy5uYW1lLFxuICAgICAgICAgICAgICB3aWRnZXRzRGlmZmVyZW5jZTogMFxuICAgICAgICAgIH07XG4gICAgICAgICAgc3RkTG9nKGBQYWNrYWdlIHRlc3Rpbmc6IFVuaGFuZGxlZCBFeGNlcHRpb246ICR7ZXJyb3J9YCk7XG5cbiAgICAgICAgICByZXN1bHRzLnB1c2goey4uLnBhcmFtcywgJ2ZsYWtpbmcnOiBERy5UZXN0LmlzUmVwcm9kdWNpbmcgJiYgIWVycm9yfSk7XG4gICAgICAgICAgKDxhbnk+cGFyYW1zKS5wYWNrYWdlID0gcGFja2FnZV8ubmFtZTtcbiAgICAgICAgICBhd2FpdCBncm9rLnNoZWxsLnJlcG9ydFRlc3QoJ3BhY2thZ2UnLCBwYXJhbXMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRSZXN1bHQoeDogYW55KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgcmV0dXJuIGAke3gudG9TdHJpbmcoKX1cXG4ke3guc3RhY2sgPyAoYXdhaXQgREcuTG9nZ2VyLnRyYW5zbGF0ZVN0YWNrVHJhY2UoeC5zdGFjaykpIDogJyd9YDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZXhlY1Rlc3QodDogVGVzdCwgcHJlZGljYXRlOiBzdHJpbmcgfCB1bmRlZmluZWQsIGxvZ3M6IGFueVtdLFxuICB0ZXN0VGltZW91dD86IG51bWJlciwgcGFja2FnZU5hbWU/OiBzdHJpbmcsIHZlcmJvc2U/OiBib29sZWFuXG4pOiBQcm9taXNlPFRlc3RSZXN1bHQgfCB1bmRlZmluZWQ+IHtcbiAgbG9ncy5sZW5ndGggPSAwO1xuICBsZXQgcjogVGVzdFJlc3VsdDtcbiAgbGV0IHR5cGU6IHN0cmluZyA9ICdwYWNrYWdlJztcbiAgY29uc3QgZmlsdGVyID0gcHJlZGljYXRlICE9IHVuZGVmaW5lZCAmJiAodC5uYW1lLnRvTG93ZXJDYXNlKCkgIT09IHByZWRpY2F0ZS50b0xvd2VyQ2FzZSgpKTtcbiAgbGV0IHNraXAgPSB0Lm9wdGlvbnM/LnNraXBSZWFzb24gfHwgZmlsdGVyO1xuICBsZXQgc2tpcFJlYXNvbiA9IGZpbHRlciA/ICdza2lwcGVkJyA6IHQub3B0aW9ucz8uc2tpcFJlYXNvbjtcblxuICBpZiAoREcuVGVzdC5pc0luQmVuY2htYXJrICYmICF0Lm9wdGlvbnM/LmJlbmNobWFyaykge1xuICAgIHN0ZExvZyhgUGFja2FnZSB0ZXN0aW5nOiBTa2lwcGVkIHt7JHt0LmNhdGVnb3J5fX19IHt7JHt0Lm5hbWV9fX0gZG9lc250IGF2YWlsYWJsZSBpbiBiZW5jaG1hcmsgbW9kZWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBpZiAoc2tpcCAmJiAhREcuVGVzdC5pc0luQmVuY2htYXJrKVxuICAgIHN0ZExvZyhgUGFja2FnZSB0ZXN0aW5nOiBTa2lwcGVkIHt7JHt0LmNhdGVnb3J5fX19IHt7JHt0Lm5hbWV9fX1gKTtcbiAgaWYgKCFza2lwKVxuICAgIHN0ZExvZyhgUGFja2FnZSB0ZXN0aW5nOiBTdGFydGVkIHt7JHt0LmNhdGVnb3J5fX19IHt7JHt0Lm5hbWV9fX1gKTtcbiAgY29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpO1xuICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZShzdGFydCkudG9JU09TdHJpbmcoKTtcbiAgdHJ5IHtcbiAgICBpZiAoc2tpcClcbiAgICAgIHIgPSB7IG5hbWU6IHQubmFtZSwgb3duZXI6dC5vcHRpb25zPy5vd25lciA/PyAnJywgY2F0ZWdvcnk6IHQuY2F0ZWdvcnksIGxvZ3M6ICcnLCBkYXRlOiBzdGFydERhdGUsIHN1Y2Nlc3M6IHRydWUsIHJlc3VsdDogc2tpcFJlYXNvbiEsIG1zOiAwLCBza2lwcGVkOiB0cnVlLCBwYWNrYWdlOiBwYWNrYWdlTmFtZSA/PyAnJywgZmxha2luZzogREcuVGVzdC5pc1JlcHJvZHVjaW5nfTtcbiAgICBlbHNlIHtcbiAgICAgIGxldCB0aW1lb3V0XyA9IHRlc3RUaW1lb3V0ID8/IFNUQU5EQVJUX1RJTUVPVVQ7XG5cbiAgICAgIGlmIChERy5UZXN0LmlzUHJvZmlsaW5nKVxuICAgICAgICBjb25zb2xlLnByb2ZpbGUoYCR7dC5jYXRlZ29yeX06ICR7dC5uYW1lfWApO1xuXG4gICAgICByID0geyBuYW1lOiB0Lm5hbWUsIG93bmVyOnQub3B0aW9ucz8ub3duZXIgPz8gJycsIGNhdGVnb3J5OiB0LmNhdGVnb3J5LCBsb2dzOiAnJywgZGF0ZTogc3RhcnREYXRlLCBzdWNjZXNzOiB0cnVlLCByZXN1bHQ6IChhd2FpdCB0aW1lb3V0KHQudGVzdCwgdGltZW91dF8pKS50b1N0cmluZygpID8/ICdPSycsIG1zOiAwLCBza2lwcGVkOiBmYWxzZSAsIHBhY2thZ2U6IHBhY2thZ2VOYW1lID8/ICcnLCBmbGFraW5nOiBERy5UZXN0LmlzUmVwcm9kdWNpbmd9O1xuXG4gICAgICBpZiAoREcuVGVzdC5pc1Byb2ZpbGluZykge1xuICAgICAgICBjb25zb2xlLnByb2ZpbGVFbmQoYCR7dC5jYXRlZ29yeX06ICR7dC5uYW1lfWApO1xuICAgICAgICBncm9rLnNoZWxsLmluZm8oYFByb2ZpbGluZyBvZiAke3QuY2F0ZWdvcnl9OiAke3QubmFtZX0gZmluaXNoZWQgXFxuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3UgaGF2ZSBvcGVuZWQgRGV2VG9vbHMgKEYxMikgLyBQZXJmb3JtYW5jZSBwYW5lbCBiZWZvcmUgdGVzdCBzdGFydHMuYCk7XG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoICh4OiBhbnkpIHtcbiAgICBzdGRFcnJvcih4KTtcbiAgICByID0geyBuYW1lOiB0Lm5hbWUsIG93bmVyOnQub3B0aW9ucz8ub3duZXIgPz8gJycsIGNhdGVnb3J5OiB0LmNhdGVnb3J5LCBsb2dzOiAnJywgZGF0ZTogc3RhcnREYXRlLCBzdWNjZXNzOiBmYWxzZSwgcmVzdWx0OiBhd2FpdCBnZXRSZXN1bHQoeCksIG1zOiAwLCBza2lwcGVkOiBmYWxzZSwgcGFja2FnZTogcGFja2FnZU5hbWUgPz8gJycsIGZsYWtpbmc6IGZhbHNlfTtcbiAgfVxuICBpZiAodC5vcHRpb25zPy5pc0FnZ3JlZ2F0ZWQgJiYgci5yZXN1bHQuY29uc3RydWN0b3IgPT09IERHLkRhdGFGcmFtZSkge1xuICAgIGNvbnN0IGNvbCA9IHIucmVzdWx0LmNvbCgnc3VjY2VzcycpO1xuICAgIGlmIChjb2wpXG4gICAgICByLnN1Y2Nlc3MgPSBjb2wuc3RhdHMuc3VtID09PSBjb2wubGVuZ3RoO1xuICAgIGlmICghdmVyYm9zZSkge1xuICAgICAgY29uc3QgZGYgPSByLnJlc3VsdDtcbiAgICAgIGRmLmNvbHVtbnMucmVtb3ZlKCdzdGFjaycpO1xuICAgICAgZGYucm93cy5yZW1vdmVXaGVyZSgocikgPT4gci5nZXQoJ3N1Y2Nlc3MnKSk7XG4gICAgICByLnJlc3VsdCA9IGRmO1xuICAgIH1cbiAgICByLnJlc3VsdCA9IHIucmVzdWx0LnRvQ3N2KCk7XG4gIH1cbiAgci5sb2dzID0gbG9ncy5qb2luKCdcXG4nKTtcbiAgci5tcyA9IERhdGUubm93KCkgLSBzdGFydDtcbiAgaWYgKCFza2lwKVxuICAgIHN0ZExvZyhgUGFja2FnZSB0ZXN0aW5nOiBGaW5pc2hlZCB7eyR7dC5jYXRlZ29yeX19fSB7eyR7dC5uYW1lfX19IHdpdGgge3ske3Iuc3VjY2VzcyA/ICdzdWNjZXNzJyA6ICdlcnJvcid9fX0gZm9yICR7ci5tc30gbXNgKTtcbiAgaWYgKCFyLnN1Y2Nlc3MpIHtcbiAgICAgIHN0ZExvZyhgUGFja2FnZSB0ZXN0aW5nOiBSZXN1bHQgZm9yIHt7JHt0LmNhdGVnb3J5fX19IHt7JHt0Lm5hbWV9fX06ICR7ci5yZXN1bHR9YCk7XG4gIH1cbiAgci5jYXRlZ29yeSA9IHQuY2F0ZWdvcnk7XG4gIHIubmFtZSA9IHQubmFtZTtcbiAgci5vd25lciA9IHQub3B0aW9ucz8ub3duZXIgPz8gJyc7XG4gIGlmICghZmlsdGVyKSB7XG4gICAgbGV0IHBhcmFtcyA9IHtcbiAgICAgICdzdWNjZXNzJzogci5zdWNjZXNzLCAncmVzdWx0Jzogci5yZXN1bHQsICdtcyc6IHIubXMsICdkYXRlJzogci5kYXRlLFxuICAgICAgJ3NraXBwZWQnOiByLnNraXBwZWQsICdjYXRlZ29yeSc6IHQuY2F0ZWdvcnksICduYW1lJzogdC5uYW1lLCAnbG9ncyc6IHIubG9ncywgJ293bmVyJzogci5vd25lcixcbiAgICAgICdmbGFraW5nJzogREcuVGVzdC5pc1JlcHJvZHVjaW5nICYmIHIuc3VjY2VzcyxcbiAgICAgICdwYWNrYWdlJzogci5wYWNrYWdlXG4gICAgfTtcbiAgICBpZiAoci5yZXN1bHQuY29uc3RydWN0b3IgPT0gT2JqZWN0KSB7XG4gICAgICBjb25zdCByZXMgPSBPYmplY3Qua2V5cyhyLnJlc3VsdCkucmVkdWNlKChhY2MsIGspID0+ICh7IC4uLmFjYywgWydyZXN1bHQuJyArIGtdOiByLnJlc3VsdFtrXSB9KSwge30pO1xuICAgICAgcGFyYW1zID0geyAuLi5wYXJhbXMsIC4uLnJlcyB9O1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMucmVzdWx0IGluc3RhbmNlb2YgREcuRGF0YUZyYW1lKVxuICAgICAgcGFyYW1zLnJlc3VsdCA9IEpTT04uc3RyaW5naWZ5KHBhcmFtcy5yZXN1bHQ/LnRvSnNvbigpKSB8fCAnJztcbiAgICBhd2FpdCBncm9rLnNoZWxsLnJlcG9ydFRlc3QodHlwZSwgcGFyYW1zKTtcbiAgfVxuICByZXR1cm4gcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNodWZmbGUoYXJyYXk6IGFueVtdKTogYW55W10ge1xuICBjb25zdCBuZXdBcnIgPSBhcnJheS5zbGljZSgpO1xuICBuZXdBcnIuc29ydCgoKSA9PiBNYXRoLnJhbmRvbSgpIC0gMC41KTtcbiAgcmV0dXJuIG5ld0Fycjtcbn1cblxuLyogV2FpdHMgW21zXSBtaWxsaXNlY29uZHMgKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWxheShtczogbnVtYmVyKSB7XG4gIGF3YWl0IG5ldyBQcm9taXNlKChyKSA9PiBzZXRUaW1lb3V0KHIsIG1zKSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhd2FpdENoZWNrKGNoZWNrSGFuZGxlcjogKCkgPT4gYm9vbGVhbixcbiAgZXJyb3I6IHN0cmluZyA9ICdUaW1lb3V0IGV4Y2VlZGVkJywgd2FpdDogbnVtYmVyID0gNTAwLCBpbnRlcnZhbDogbnVtYmVyID0gNTApOiBQcm9taXNlPGFueT4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgY2xlYXJJbnRlcnZhbChpbnRlcnZhbElkKTtcbiAgICAgIHJlamVjdChuZXcgRXJyb3IoZXJyb3IpKTtcbiAgICB9LCB3YWl0KTtcbiAgICAvLyBAdHMtaWdub3JlXG4gICAgY29uc3QgaW50ZXJ2YWxJZDogVGltZW91dCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIGlmIChjaGVja0hhbmRsZXIoKSkge1xuICAgICAgICBjbGVhckludGVydmFsKGludGVydmFsSWQpO1xuICAgICAgICByZXNvbHZlKG51bGwpO1xuICAgICAgfVxuICAgIH0sIGludGVydmFsKTtcbiAgfSk7XG59XG5cbi8vIFJldHVybnMgdGVzdCBleGVjdXRpb24gcmVzdWx0IG9yIGFuIGVycm9yIGluIGNhc2Ugb2YgdGltZW91dFxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRpbWVvdXQoZnVuYzogKCkgPT4gUHJvbWlzZTxhbnk+LCB0ZXN0VGltZW91dDogbnVtYmVyLCB0aW1lb3V0UmVhc29uOiBzdHJpbmcgPSAnRVhFQ1VUSU9OIFRJTUVPVVQnKTogUHJvbWlzZTxhbnk+IHtcbiAgbGV0IHRpbWVvdXQ6IGFueSA9IG51bGw7XG4gIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2U8YW55PigoXywgcmVqZWN0KSA9PiB7XG4gICAgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1wcm9taXNlLXJlamVjdC1lcnJvcnNcbiAgICAgIHJlamVjdCh0aW1lb3V0UmVhc29uKTtcbiAgICB9LCB0ZXN0VGltZW91dCk7XG4gIH0pO1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBQcm9taXNlLnJhY2UoW2Z1bmMoKSwgdGltZW91dFByb21pc2VdKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBpZiAodGltZW91dClcbiAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNEaWFsb2dQcmVzZW50KGRpYWxvZ1RpdGxlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3QgZGlhbG9ncyA9IERHLkRpYWxvZy5nZXRPcGVuRGlhbG9ncygpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGRpYWxvZ3MubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoZGlhbG9nc1tpXS50aXRsZSA9PSBkaWFsb2dUaXRsZSlcbiAgICAgIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqIEV4cGVjdHMgYW4gYXN5bmNocm9ub3VzIHtAbGluayBhY3Rpb259IHRvIHRocm93IGFuIGV4Y2VwdGlvbi4gVXNlIHtAbGluayBjaGVja30gdG8gcGVyZm9ybVxuICogZGVlcGVyIGluc3BlY3Rpb24gb2YgdGhlIGV4Y2VwdGlvbiBpZiBuZWNlc3NhcnkuXG4gKiBAcGFyYW0gIHtmdW5jdGlvbigpOiBQcm9taXNlPHZvaWQ+fSBhY3Rpb25cbiAqIEBwYXJhbSAge2Z1bmN0aW9uKGFueSk6IGJvb2xlYW59IGNoZWNrXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwZWN0RXhjZXB0aW9uQXN5bmMoYWN0aW9uOiAoKSA9PiBQcm9taXNlPHZvaWQ+LFxuICBjaGVjaz86IChleGNlcHRpb246IGFueSkgPT4gYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICBsZXQgY2F1Z2h0OiBib29sZWFuID0gZmFsc2U7XG4gIGxldCBjaGVja2VkOiBib29sZWFuID0gZmFsc2U7XG4gIHRyeSB7XG4gICAgYXdhaXQgYWN0aW9uKCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjYXVnaHQgPSB0cnVlO1xuICAgIGNoZWNrZWQgPSAhY2hlY2sgfHwgY2hlY2soZSk7XG4gIH0gZmluYWxseSB7XG4gICAgaWYgKCFjYXVnaHQpXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FuIGV4Y2VwdGlvbiBpcyBleHBlY3RlZCBidXQgbm90IHRocm93bicpO1xuICAgIGlmICghY2hlY2tlZClcbiAgICAgIHRocm93IG5ldyBFcnJvcignQW4gZXhwZWN0ZWQgZXhjZXB0aW9uIGlzIHRocm93biwgYnV0IGl0IGRvZXMgbm90IHNhdGlzZnkgdGhlIGNvbmRpdGlvbicpO1xuICB9XG59XG5cbmNvbnN0IGNhdERGID0gREcuRGF0YUZyYW1lLmZyb21Db2x1bW5zKFtERy5Db2x1bW4uZnJvbVN0cmluZ3MoJ2NvbCcsIFsndmFsMScsICd2YWwyJywgJ3ZhbDMnXSldKTtcblxuLyoqXG4gKiBVbml2ZXJzYWwgdGVzdCBmb3Igdmlld2Vycy4gSXQgc2VhcmNoIHZpZXdlcnMgaW4gRE9NIGJ5IHRhZ3M6IGNhbnZhcywgc3ZnLCBpbWcsIGlucHV0LCBoMSwgYVxuICogQHBhcmFtICB7c3RyaW5nfSB2IFZpZXdlciBuYW1lXG4gKiBAcGFyYW0gIHtfREcuRGF0YUZyYW1lfSBkZiBEYXRhZnJhbWUgdG8gdXNlLiBTaG91bGQgaGF2ZSBhdCBsZWFzdCAzIHJvd3NcbiAqIEBwYXJhbSAge2Jvb2xlYW59IG9wdGlvbnMuZGV0ZWN0U2VtYW50aWNUeXBlcyBTcGVjaWZ5IHdoZXRoZXIgdG8gZGV0ZWN0IHNlbWFudGljIHR5cGVzIG9yIG5vdFxuICogQHBhcmFtICB7Ym9vbGVhbn0gb3B0aW9ucy5yZWFkT25seSBJZiBzZXQgdG8gdHJ1ZSwgdGhlIGRhdGFmcmFtZSB3aWxsIG5vdCBiZSBtb2RpZmllZCBkdXJpbmcgdGhlIHRlc3RcbiAqIEBwYXJhbSAge2Jvb2xlYW59IG9wdGlvbnMuYXJiaXRyYXJ5RGZUZXN0IElmIHNldCB0byBmYWxzZSwgdGVzdCBvbiBhcmJpdHJhcnkgZGF0YWZyYW1lXG4gKiAob25lIGNhdGVnb3JpY2FsIGNvbHVtbikgd2lsbCBub3QgYmUgcGVyZm9ybWVkXG4gKiBAcGFyYW0gIHtvYmplY3R9IG9wdGlvbnMgTGlzdCBvZiBvcHRpb25zIChvcHRpb25hbClcbiAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFRoZSB0ZXN0IGlzIGNvbnNpZGVyZWQgc3VjY2Vzc2Z1bCBpZiBpdCBjb21wbGV0ZXMgd2l0aG91dCBlcnJvcnNcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRlc3RWaWV3ZXIodjogc3RyaW5nLCBkZjogX0RHLkRhdGFGcmFtZSwgb3B0aW9ucz86IHtcbiAgZGV0ZWN0U2VtYW50aWNUeXBlcz86IGJvb2xlYW4sIHJlYWRPbmx5PzogYm9vbGVhbiwgYXJiaXRyYXJ5RGZUZXN0PzogYm9vbGVhbixcbiAgcGFja2FnZU5hbWU/OiBzdHJpbmcsIGF3YWl0Vmlld2VyPzogKHZpZXdlcjogX0RHLlZpZXdlcikgPT4gUHJvbWlzZTx2b2lkPlxufSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBwYWNrYWdlTmFtZSA9IG9wdGlvbnM/LnBhY2thZ2VOYW1lID8/ICcnO1xuICBpZiAob3B0aW9ucz8uZGV0ZWN0U2VtYW50aWNUeXBlcylcbiAgICBhd2FpdCBncm9rLmRhdGEuZGV0ZWN0U2VtYW50aWNUeXBlcyhkZik7XG4gIGNvbnN0IHR2ID0gZ3Jvay5zaGVsbC5hZGRUYWJsZVZpZXcoZGYpO1xuXG4gIHRyeSB7XG4gICAgLy8xLiBPcGVuLCBkbyBub3RoaW5nIGFuZCBjbG9zZVxuICAgIGF3YWl0IHRlc3RWaWV3ZXJJbnRlcm5hbCh0diwgdiwgcGFja2FnZU5hbWUsIGdyb2suZXZlbnRzLm9uVmlld2VyQWRkZWQpO1xuICAgIC8vaW4gY2FzZSB2aWV3ZXIgd2l0aCBhc3luYyByZW5kZXJpbmcgLSB3YWl0IGZvciByZW5kZXIgdG8gY29tcGxldGVcbiAgICBpZiAob3B0aW9ucz8uYXdhaXRWaWV3ZXIpXG4gICAgICBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdlckFkZGVkLCB1bmRlZmluZWQsIG9wdGlvbnMhLmF3YWl0Vmlld2VyKTtcblxuICAgIC8vMi4gT3BlbiB2aWV3ZXIsIHJ1biBzZWxlY3Rpb24sIGZpbHRlciwgZXRjLiBhbmQgY2xvc2VcbiAgICBpZiAoIW9wdGlvbnM/LnJlYWRPbmx5KSB7XG4gICAgICBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdlckFkZGVkLCBzZWxlY3RGaWx0ZXJDaGFuZ2VDdXJyZW50KTtcbiAgICAgIGlmIChvcHRpb25zPy5hd2FpdFZpZXdlcilcbiAgICAgICAgYXdhaXQgdGVzdFZpZXdlckludGVybmFsKHR2LCB2LCBwYWNrYWdlTmFtZSwgZ3Jvay5ldmVudHMub25WaWV3ZXJBZGRlZCwgc2VsZWN0RmlsdGVyQ2hhbmdlQ3VycmVudCwgb3B0aW9ucyEuYXdhaXRWaWV3ZXIpO1xuICAgIH1cblxuICAgIC8vMi4gT3BlbiB2aWV3ZXIsIGNoYW5nZSBvcHRpb25zLCBzYXZlIGxheW91dCBhbmQgY2xvc2VcbiAgICBsZXQgcHJvcHNBbmRMYXlvdXQ6IHsgbGF5b3V0OiBhbnksIHNhdmVkUHJvcHM6IGFueSB9IHwgbnVsbCA9IG51bGw7XG4gICAgcHJvcHNBbmRMYXlvdXQgPSBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdlckFkZGVkLCBjaGFuZ2VPcHRpb25zU2F2ZUxheW91dCk7XG4gICAgaWYgKG9wdGlvbnM/LmF3YWl0Vmlld2VyKVxuICAgICAgcHJvcHNBbmRMYXlvdXQgPSBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdlckFkZGVkLFxuICAgICAgICBjaGFuZ2VPcHRpb25zU2F2ZUxheW91dCwgb3B0aW9ucyEuYXdhaXRWaWV3ZXIpXG5cbiAgICAvLzMuIExvYWQgbGF5b3V0XG4gICAgYXdhaXQgdGVzdFZpZXdlckludGVybmFsKHR2LCB2LCBwYWNrYWdlTmFtZSwgZ3Jvay5ldmVudHMub25WaWV3TGF5b3V0QXBwbGllZCwgbG9hZExheW91dCwgdW5kZWZpbmVkLCBwcm9wc0FuZExheW91dD8ubGF5b3V0LFxuICAgICAgeyBzYXZlZFByb3BzOiBwcm9wc0FuZExheW91dD8uc2F2ZWRQcm9wcyB9KTtcbiAgICBpZiAob3B0aW9ucz8uYXdhaXRWaWV3ZXIpXG4gICAgICBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdMYXlvdXRBcHBsaWVkLCBsb2FkTGF5b3V0LCBvcHRpb25zIS5hd2FpdFZpZXdlcixcbiAgICAgICAgcHJvcHNBbmRMYXlvdXQ/LmxheW91dCwgeyBzYXZlZFByb3BzOiBwcm9wc0FuZExheW91dD8uc2F2ZWRQcm9wcyB9KTtcblxuICAgIC8vNC4gT3BlbiB2aWV3ZXIgb24gYXJiaXRhcnkgZGF0YXNldFxuICAgIGlmIChvcHRpb25zPy5hcmJpdHJhcnlEZlRlc3QgIT09IGZhbHNlKSB7XG4gICAgICB0di5kYXRhRnJhbWUgPSBjYXRERjtcbiAgICAgIGF3YWl0IGRlbGF5KDUwKTtcbiAgICAgIGF3YWl0IHRlc3RWaWV3ZXJJbnRlcm5hbCh0diwgdiwgcGFja2FnZU5hbWUsIGdyb2suZXZlbnRzLm9uVmlld2VyQWRkZWQpO1xuICAgICAgaWYgKG9wdGlvbnM/LmF3YWl0Vmlld2VyKVxuICAgICAgICBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdlckFkZGVkLCB1bmRlZmluZWQsIG9wdGlvbnMhLmF3YWl0Vmlld2VyKTtcbiAgICB9XG5cbiAgICAvLzUuIENhbGwgcG9zdHBvbmVkIGZpbHRlcmluZ1xuICAgIGF3YWl0IHRlc3RWaWV3ZXJJbnRlcm5hbCh0diwgdiwgcGFja2FnZU5hbWUsIGdyb2suZXZlbnRzLm9uVmlld2VyQWRkZWQsIGZpbHRlckFzeW5jKTtcbiAgICBpZiAob3B0aW9ucz8uYXdhaXRWaWV3ZXIpXG4gICAgICBhd2FpdCB0ZXN0Vmlld2VySW50ZXJuYWwodHYsIHYsIHBhY2thZ2VOYW1lLCBncm9rLmV2ZW50cy5vblZpZXdlckFkZGVkLCBmaWx0ZXJBc3luYywgb3B0aW9ucyEuYXdhaXRWaWV3ZXIpO1xuXG4gIH0gZmluYWxseSB7XG4gICAgLy8gY2xvc2VBbGwoKSBpcyBoYW5kbGluZyBieSBjb21tb24gdGVzdCB3b3JrZmxvd1xuICAgIC8vIGdyb2suc2hlbGwuY2xvc2VBbGwoKTtcbiAgICAvLyBERy5CYWxsb29uLmNsb3NlQWxsKCk7XG4gIH1cbn1cbiJdfQ==","!function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define(e):(t=\"undefined\"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){\"use strict\";var t=1e3,e=6e4,n=36e5,r=\"millisecond\",i=\"second\",s=\"minute\",u=\"hour\",a=\"day\",o=\"week\",c=\"month\",f=\"quarter\",h=\"year\",d=\"date\",l=\"Invalid Date\",$=/^(\\d{4})[-/]?(\\d{1,2})?[-/]?(\\d{0,2})[Tt\\s]*(\\d{1,2})?:?(\\d{1,2})?:?(\\d{1,2})?[.:]?(\\d+)?$/,y=/\\[([^\\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:\"en\",weekdays:\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),months:\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),ordinal:function(t){var e=[\"th\",\"st\",\"nd\",\"rd\"],n=t%100;return\"[\"+t+(e[(n-20)%10]||e[n]||e[0])+\"]\"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:\"\"+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?\"+\":\"-\")+m(r,2,\"0\")+\":\"+m(i,2,\"0\")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,c),s=n-i<0,u=e.clone().add(r+(s?-1:1),c);return+(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return{M:c,y:h,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:f}[t]||String(t||\"\").toLowerCase().replace(/s$/,\"\")},u:function(t){return void 0===t}},g=\"en\",D={};D[g]=M;var p=\"$isDayjsObject\",S=function(t){return t instanceof _||!(!t||!t[p])},w=function t(e,n,r){var i;if(!e)return g;if(\"string\"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split(\"-\");if(!i&&u.length>1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n=\"object\"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if(\"string\"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||\"0\").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<O(t)},m.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!b.u(e)||e,f=b.p(t),l=function(t,e){var i=b.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return b.w(n.toDate()[t].apply(n.toDate(\"s\"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v=\"set\"+(this.$u?\"UTC\":\"\");switch(f){case h:return r?l(1,0):l(31,11);case c:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+\"Hours\",0);case u:return $(v+\"Minutes\",1);case s:return $(v+\"Seconds\",2);case i:return $(v+\"Milliseconds\",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,!1)},m.$set=function(t,e){var n,o=b.p(t),f=\"set\"+(this.$u?\"UTC\":\"\"),l=(n={},n[a]=f+\"Date\",n[d]=f+\"Date\",n[c]=f+\"Month\",n[h]=f+\"FullYear\",n[u]=f+\"Hours\",n[s]=f+\"Minutes\",n[i]=f+\"Seconds\",n[r]=f+\"Milliseconds\",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===c||o===h){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[b.p(t)]()},m.add=function(r,f){var d,l=this;r=Number(r);var $=b.p(f),y=function(t){var e=O(l);return b.w(e.date(e.date()+Math.round(t*r)),l)};if($===c)return this.set(c,this.$M+r);if($===h)return this.set(h,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return b.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||\"YYYY-MM-DDTHH:mm:ssZ\",i=b.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,c=n.months,f=n.meridiem,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},d=function(t){return b.s(s%12||12,t,\"0\")},$=f||function(t,e,n){var r=t<12?\"AM\":\"PM\";return n?r.toLowerCase():r};return r.replace(y,(function(t,r){return r||function(t){switch(t){case\"YY\":return String(e.$y).slice(-2);case\"YYYY\":return b.s(e.$y,4,\"0\");case\"M\":return a+1;case\"MM\":return b.s(a+1,2,\"0\");case\"MMM\":return h(n.monthsShort,a,c,3);case\"MMMM\":return h(c,a);case\"D\":return e.$D;case\"DD\":return b.s(e.$D,2,\"0\");case\"d\":return String(e.$W);case\"dd\":return h(n.weekdaysMin,e.$W,o,2);case\"ddd\":return h(n.weekdaysShort,e.$W,o,3);case\"dddd\":return o[e.$W];case\"H\":return String(s);case\"HH\":return b.s(s,2,\"0\");case\"h\":return d(1);case\"hh\":return d(2);case\"a\":return $(s,u,!0);case\"A\":return $(s,u,!1);case\"m\":return String(u);case\"mm\":return b.s(u,2,\"0\");case\"s\":return String(e.$s);case\"ss\":return b.s(e.$s,2,\"0\");case\"SSS\":return b.s(e.$ms,3,\"0\");case\"Z\":return i}return null}(t)||i.replace(\":\",\"\")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=this,M=b.p(d),m=O(r),v=(m.utcOffset()-this.utcOffset())*e,g=this-m,D=function(){return b.m(y,m)};switch(M){case h:$=D()/12;break;case c:$=D();break;case f:$=D()/3;break;case o:$=(g-v)/6048e5;break;case a:$=(g-v)/864e5;break;case u:$=g/n;break;case s:$=g/e;break;case i:$=g/t;break;default:$=g}return l?$:b.a($)},m.daysInMonth=function(){return this.endOf(c).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=w(t,e,!0);return r&&(n.$L=r),n},m.clone=function(){return b.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),k=_.prototype;return O.prototype=k,[[\"$ms\",r],[\"$s\",i],[\"$m\",s],[\"$H\",u],[\"$W\",a],[\"$M\",c],[\"$y\",h],[\"$D\",d]].forEach((function(t){k[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),O.extend=function(t,e){return t.$i||(t(e,_,O),t.$i=!0),O},O.locale=w,O.isDayjs=S,O.unix=function(t){return O(1e3*t)},O.en=D[g],O.Ls=D,O.p={},O}));","(function (root, factory) {\n // Hack to make all exports of this module sha256 function object properties.\n var exports = {};\n factory(exports);\n var sha256 = exports[\"default\"];\n for (var k in exports) {\n sha256[k] = exports[k];\n }\n \n if (typeof module === 'object' && typeof module.exports === 'object') {\n module.exports = sha256;\n } else if (typeof define === 'function' && define.amd) {\n define(function() { return sha256; }); \n } else {\n root.sha256 = sha256;\n }\n})(this, function(exports) {\n\"use strict\";\nexports.__esModule = true;\n// SHA-256 (+ HMAC and PBKDF2) for JavaScript.\n//\n// Written in 2014-2016 by Dmitry Chestnykh.\n// Public domain, no warranty.\n//\n// Functions (accept and return Uint8Arrays):\n//\n// sha256(message) -> hash\n// sha256.hmac(key, message) -> mac\n// sha256.pbkdf2(password, salt, rounds, dkLen) -> dk\n//\n// Classes:\n//\n// new sha256.Hash()\n// new sha256.HMAC(key)\n//\nexports.digestLength = 32;\nexports.blockSize = 64;\n// SHA-256 constants\nvar K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,\n 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,\n 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,\n 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,\n 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,\n 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,\n 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,\n 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,\n 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,\n 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n]);\nfunction hashBlocks(w, v, p, pos, len) {\n var a, b, c, d, e, f, g, h, u, i, j, t1, t2;\n while (len >= 64) {\n a = v[0];\n b = v[1];\n c = v[2];\n d = v[3];\n e = v[4];\n f = v[5];\n g = v[6];\n h = v[7];\n for (i = 0; i < 16; i++) {\n j = pos + i * 4;\n w[i] = (((p[j] & 0xff) << 24) | ((p[j + 1] & 0xff) << 16) |\n ((p[j + 2] & 0xff) << 8) | (p[j + 3] & 0xff));\n }\n for (i = 16; i < 64; i++) {\n u = w[i - 2];\n t1 = (u >>> 17 | u << (32 - 17)) ^ (u >>> 19 | u << (32 - 19)) ^ (u >>> 10);\n u = w[i - 15];\n t2 = (u >>> 7 | u << (32 - 7)) ^ (u >>> 18 | u << (32 - 18)) ^ (u >>> 3);\n w[i] = (t1 + w[i - 7] | 0) + (t2 + w[i - 16] | 0);\n }\n for (i = 0; i < 64; i++) {\n t1 = (((((e >>> 6 | e << (32 - 6)) ^ (e >>> 11 | e << (32 - 11)) ^\n (e >>> 25 | e << (32 - 25))) + ((e & f) ^ (~e & g))) | 0) +\n ((h + ((K[i] + w[i]) | 0)) | 0)) | 0;\n t2 = (((a >>> 2 | a << (32 - 2)) ^ (a >>> 13 | a << (32 - 13)) ^\n (a >>> 22 | a << (32 - 22))) + ((a & b) ^ (a & c) ^ (b & c))) | 0;\n h = g;\n g = f;\n f = e;\n e = (d + t1) | 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) | 0;\n }\n v[0] += a;\n v[1] += b;\n v[2] += c;\n v[3] += d;\n v[4] += e;\n v[5] += f;\n v[6] += g;\n v[7] += h;\n pos += 64;\n len -= 64;\n }\n return pos;\n}\n// Hash implements SHA256 hash algorithm.\nvar Hash = /** @class */ (function () {\n function Hash() {\n this.digestLength = exports.digestLength;\n this.blockSize = exports.blockSize;\n // Note: Int32Array is used instead of Uint32Array for performance reasons.\n this.state = new Int32Array(8); // hash state\n this.temp = new Int32Array(64); // temporary state\n this.buffer = new Uint8Array(128); // buffer for data to hash\n this.bufferLength = 0; // number of bytes in buffer\n this.bytesHashed = 0; // number of total bytes hashed\n this.finished = false; // indicates whether the hash was finalized\n this.reset();\n }\n // Resets hash state making it possible\n // to re-use this instance to hash other data.\n Hash.prototype.reset = function () {\n this.state[0] = 0x6a09e667;\n this.state[1] = 0xbb67ae85;\n this.state[2] = 0x3c6ef372;\n this.state[3] = 0xa54ff53a;\n this.state[4] = 0x510e527f;\n this.state[5] = 0x9b05688c;\n this.state[6] = 0x1f83d9ab;\n this.state[7] = 0x5be0cd19;\n this.bufferLength = 0;\n this.bytesHashed = 0;\n this.finished = false;\n return this;\n };\n // Cleans internal buffers and re-initializes hash state.\n Hash.prototype.clean = function () {\n for (var i = 0; i < this.buffer.length; i++) {\n this.buffer[i] = 0;\n }\n for (var i = 0; i < this.temp.length; i++) {\n this.temp[i] = 0;\n }\n this.reset();\n };\n // Updates hash state with the given data.\n //\n // Optionally, length of the data can be specified to hash\n // fewer bytes than data.length.\n //\n // Throws error when trying to update already finalized hash:\n // instance must be reset to use it again.\n Hash.prototype.update = function (data, dataLength) {\n if (dataLength === void 0) { dataLength = data.length; }\n if (this.finished) {\n throw new Error(\"SHA256: can't update because hash was finished.\");\n }\n var dataPos = 0;\n this.bytesHashed += dataLength;\n if (this.bufferLength > 0) {\n while (this.bufferLength < 64 && dataLength > 0) {\n this.buffer[this.bufferLength++] = data[dataPos++];\n dataLength--;\n }\n if (this.bufferLength === 64) {\n hashBlocks(this.temp, this.state, this.buffer, 0, 64);\n this.bufferLength = 0;\n }\n }\n if (dataLength >= 64) {\n dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength);\n dataLength %= 64;\n }\n while (dataLength > 0) {\n this.buffer[this.bufferLength++] = data[dataPos++];\n dataLength--;\n }\n return this;\n };\n // Finalizes hash state and puts hash into out.\n //\n // If hash was already finalized, puts the same value.\n Hash.prototype.finish = function (out) {\n if (!this.finished) {\n var bytesHashed = this.bytesHashed;\n var left = this.bufferLength;\n var bitLenHi = (bytesHashed / 0x20000000) | 0;\n var bitLenLo = bytesHashed << 3;\n var padLength = (bytesHashed % 64 < 56) ? 64 : 128;\n this.buffer[left] = 0x80;\n for (var i = left + 1; i < padLength - 8; i++) {\n this.buffer[i] = 0;\n }\n this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff;\n this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff;\n this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff;\n this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff;\n this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff;\n this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff;\n this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff;\n this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff;\n hashBlocks(this.temp, this.state, this.buffer, 0, padLength);\n this.finished = true;\n }\n for (var i = 0; i < 8; i++) {\n out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff;\n out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;\n out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;\n out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;\n }\n return this;\n };\n // Returns the final hash digest.\n Hash.prototype.digest = function () {\n var out = new Uint8Array(this.digestLength);\n this.finish(out);\n return out;\n };\n // Internal function for use in HMAC for optimization.\n Hash.prototype._saveState = function (out) {\n for (var i = 0; i < this.state.length; i++) {\n out[i] = this.state[i];\n }\n };\n // Internal function for use in HMAC for optimization.\n Hash.prototype._restoreState = function (from, bytesHashed) {\n for (var i = 0; i < this.state.length; i++) {\n this.state[i] = from[i];\n }\n this.bytesHashed = bytesHashed;\n this.finished = false;\n this.bufferLength = 0;\n };\n return Hash;\n}());\nexports.Hash = Hash;\n// HMAC implements HMAC-SHA256 message authentication algorithm.\nvar HMAC = /** @class */ (function () {\n function HMAC(key) {\n this.inner = new Hash();\n this.outer = new Hash();\n this.blockSize = this.inner.blockSize;\n this.digestLength = this.inner.digestLength;\n var pad = new Uint8Array(this.blockSize);\n if (key.length > this.blockSize) {\n (new Hash()).update(key).finish(pad).clean();\n }\n else {\n for (var i = 0; i < key.length; i++) {\n pad[i] = key[i];\n }\n }\n for (var i = 0; i < pad.length; i++) {\n pad[i] ^= 0x36;\n }\n this.inner.update(pad);\n for (var i = 0; i < pad.length; i++) {\n pad[i] ^= 0x36 ^ 0x5c;\n }\n this.outer.update(pad);\n this.istate = new Uint32Array(8);\n this.ostate = new Uint32Array(8);\n this.inner._saveState(this.istate);\n this.outer._saveState(this.ostate);\n for (var i = 0; i < pad.length; i++) {\n pad[i] = 0;\n }\n }\n // Returns HMAC state to the state initialized with key\n // to make it possible to run HMAC over the other data with the same\n // key without creating a new instance.\n HMAC.prototype.reset = function () {\n this.inner._restoreState(this.istate, this.inner.blockSize);\n this.outer._restoreState(this.ostate, this.outer.blockSize);\n return this;\n };\n // Cleans HMAC state.\n HMAC.prototype.clean = function () {\n for (var i = 0; i < this.istate.length; i++) {\n this.ostate[i] = this.istate[i] = 0;\n }\n this.inner.clean();\n this.outer.clean();\n };\n // Updates state with provided data.\n HMAC.prototype.update = function (data) {\n this.inner.update(data);\n return this;\n };\n // Finalizes HMAC and puts the result in out.\n HMAC.prototype.finish = function (out) {\n if (this.outer.finished) {\n this.outer.finish(out);\n }\n else {\n this.inner.finish(out);\n this.outer.update(out, this.digestLength).finish(out);\n }\n return this;\n };\n // Returns message authentication code.\n HMAC.prototype.digest = function () {\n var out = new Uint8Array(this.digestLength);\n this.finish(out);\n return out;\n };\n return HMAC;\n}());\nexports.HMAC = HMAC;\n// Returns SHA256 hash of data.\nfunction hash(data) {\n var h = (new Hash()).update(data);\n var digest = h.digest();\n h.clean();\n return digest;\n}\nexports.hash = hash;\n// Function hash is both available as module.hash and as default export.\nexports[\"default\"] = hash;\n// Returns HMAC-SHA256 of data under the key.\nfunction hmac(key, data) {\n var h = (new HMAC(key)).update(data);\n var digest = h.digest();\n h.clean();\n return digest;\n}\nexports.hmac = hmac;\n// Fills hkdf buffer like this:\n// T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)\nfunction fillBuffer(buffer, hmac, info, counter) {\n // Counter is a byte value: check if it overflowed.\n var num = counter[0];\n if (num === 0) {\n throw new Error(\"hkdf: cannot expand more\");\n }\n // Prepare HMAC instance for new data with old key.\n hmac.reset();\n // Hash in previous output if it was generated\n // (i.e. counter is greater than 1).\n if (num > 1) {\n hmac.update(buffer);\n }\n // Hash in info if it exists.\n if (info) {\n hmac.update(info);\n }\n // Hash in the counter.\n hmac.update(counter);\n // Output result to buffer and clean HMAC instance.\n hmac.finish(buffer);\n // Increment counter inside typed array, this works properly.\n counter[0]++;\n}\nvar hkdfSalt = new Uint8Array(exports.digestLength); // Filled with zeroes.\nfunction hkdf(key, salt, info, length) {\n if (salt === void 0) { salt = hkdfSalt; }\n if (length === void 0) { length = 32; }\n var counter = new Uint8Array([1]);\n // HKDF-Extract uses salt as HMAC key, and key as data.\n var okm = hmac(salt, key);\n // Initialize HMAC for expanding with extracted key.\n // Ensure no collisions with `hmac` function.\n var hmac_ = new HMAC(okm);\n // Allocate buffer.\n var buffer = new Uint8Array(hmac_.digestLength);\n var bufpos = buffer.length;\n var out = new Uint8Array(length);\n for (var i = 0; i < length; i++) {\n if (bufpos === buffer.length) {\n fillBuffer(buffer, hmac_, info, counter);\n bufpos = 0;\n }\n out[i] = buffer[bufpos++];\n }\n hmac_.clean();\n buffer.fill(0);\n counter.fill(0);\n return out;\n}\nexports.hkdf = hkdf;\n// Derives a key from password and salt using PBKDF2-HMAC-SHA256\n// with the given number of iterations.\n//\n// The number of bytes returned is equal to dkLen.\n//\n// (For better security, avoid dkLen greater than hash length - 32 bytes).\nfunction pbkdf2(password, salt, iterations, dkLen) {\n var prf = new HMAC(password);\n var len = prf.digestLength;\n var ctr = new Uint8Array(4);\n var t = new Uint8Array(len);\n var u = new Uint8Array(len);\n var dk = new Uint8Array(dkLen);\n for (var i = 0; i * len < dkLen; i++) {\n var c = i + 1;\n ctr[0] = (c >>> 24) & 0xff;\n ctr[1] = (c >>> 16) & 0xff;\n ctr[2] = (c >>> 8) & 0xff;\n ctr[3] = (c >>> 0) & 0xff;\n prf.reset();\n prf.update(salt);\n prf.update(ctr);\n prf.finish(u);\n for (var j = 0; j < len; j++) {\n t[j] = u[j];\n }\n for (var j = 2; j <= iterations; j++) {\n prf.reset();\n prf.update(u).finish(u);\n for (var k = 0; k < len; k++) {\n t[k] ^= u[k];\n }\n }\n for (var j = 0; j < len && i * len + j < dkLen; j++) {\n dk[i * len + j] = t[j];\n }\n }\n for (var i = 0; i < len; i++) {\n t[i] = u[i] = 0;\n }\n for (var i = 0; i < 4; i++) {\n ctr[i] = 0;\n }\n prf.clean();\n return dk;\n}\nexports.pbkdf2 = pbkdf2;\n});\n","(function (window, factory) {\n if (typeof exports === 'object') {\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n define(factory);\n } else {\n window.jStat = factory();\n }\n})(this, function () {\nvar jStat = (function(Math, undefined) {\n\n// For quick reference.\nvar concat = Array.prototype.concat;\nvar slice = Array.prototype.slice;\nvar toString = Object.prototype.toString;\n\n// Calculate correction for IEEE error\n// TODO: This calculation can be improved.\nfunction calcRdx(n, m) {\n var val = n > m ? n : m;\n return Math.pow(10,\n 17 - ~~(Math.log(((val > 0) ? val : -val)) * Math.LOG10E));\n}\n\n\nvar isArray = Array.isArray || function isArray(arg) {\n return toString.call(arg) === '[object Array]';\n};\n\n\nfunction isFunction(arg) {\n return toString.call(arg) === '[object Function]';\n}\n\n\nfunction isNumber(num) {\n return (typeof num === 'number') ? num - num === 0 : false;\n}\n\n\n// Converts the jStat matrix to vector.\nfunction toVector(arr) {\n return concat.apply([], arr);\n}\n\n\n// The one and only jStat constructor.\nfunction jStat() {\n return new jStat._init(arguments);\n}\n\n\n// TODO: Remove after all references in src files have been removed.\njStat.fn = jStat.prototype;\n\n\n// By separating the initializer from the constructor it's easier to handle\n// always returning a new instance whether \"new\" was used or not.\njStat._init = function _init(args) {\n // If first argument is an array, must be vector or matrix.\n if (isArray(args[0])) {\n // Check if matrix.\n if (isArray(args[0][0])) {\n // See if a mapping function was also passed.\n if (isFunction(args[1]))\n args[0] = jStat.map(args[0], args[1]);\n // Iterate over each is faster than this.push.apply(this, args[0].\n for (var i = 0; i < args[0].length; i++)\n this[i] = args[0][i];\n this.length = args[0].length;\n\n // Otherwise must be a vector.\n } else {\n this[0] = isFunction(args[1]) ? jStat.map(args[0], args[1]) : args[0];\n this.length = 1;\n }\n\n // If first argument is number, assume creation of sequence.\n } else if (isNumber(args[0])) {\n this[0] = jStat.seq.apply(null, args);\n this.length = 1;\n\n // Handle case when jStat object is passed to jStat.\n } else if (args[0] instanceof jStat) {\n // Duplicate the object and pass it back.\n return jStat(args[0].toArray());\n\n // Unexpected argument value, return empty jStat object.\n // TODO: This is strange behavior. Shouldn't this throw or some such to let\n // the user know they had bad arguments?\n } else {\n this[0] = [];\n this.length = 1;\n }\n\n return this;\n};\njStat._init.prototype = jStat.prototype;\njStat._init.constructor = jStat;\n\n\n// Utility functions.\n// TODO: for internal use only?\njStat.utils = {\n calcRdx: calcRdx,\n isArray: isArray,\n isFunction: isFunction,\n isNumber: isNumber,\n toVector: toVector\n};\n\n\njStat._random_fn = Math.random;\njStat.setRandom = function setRandom(fn) {\n if (typeof fn !== 'function')\n throw new TypeError('fn is not a function');\n jStat._random_fn = fn;\n};\n\n\n// Easily extend the jStat object.\n// TODO: is this seriously necessary?\njStat.extend = function extend(obj) {\n var i, j;\n\n if (arguments.length === 1) {\n for (j in obj)\n jStat[j] = obj[j];\n return this;\n }\n\n for (i = 1; i < arguments.length; i++) {\n for (j in arguments[i])\n obj[j] = arguments[i][j];\n }\n\n return obj;\n};\n\n\n// Returns the number of rows in the matrix.\njStat.rows = function rows(arr) {\n return arr.length || 1;\n};\n\n\n// Returns the number of columns in the matrix.\njStat.cols = function cols(arr) {\n return arr[0].length || 1;\n};\n\n\n// Returns the dimensions of the object { rows: i, cols: j }\njStat.dimensions = function dimensions(arr) {\n return {\n rows: jStat.rows(arr),\n cols: jStat.cols(arr)\n };\n};\n\n\n// Returns a specified row as a vector or return a sub matrix by pick some rows\njStat.row = function row(arr, index) {\n if (isArray(index)) {\n return index.map(function(i) {\n return jStat.row(arr, i);\n })\n }\n return arr[index];\n};\n\n\n// return row as array\n// rowa([[1,2],[3,4]],0) -> [1,2]\njStat.rowa = function rowa(arr, i) {\n return jStat.row(arr, i);\n};\n\n\n// Returns the specified column as a vector or return a sub matrix by pick some\n// columns\njStat.col = function col(arr, index) {\n if (isArray(index)) {\n var submat = jStat.arange(arr.length).map(function() {\n return new Array(index.length);\n });\n index.forEach(function(ind, i){\n jStat.arange(arr.length).forEach(function(j) {\n submat[j][i] = arr[j][ind];\n });\n });\n return submat;\n }\n var column = new Array(arr.length);\n for (var i = 0; i < arr.length; i++)\n column[i] = [arr[i][index]];\n return column;\n};\n\n\n// return column as array\n// cola([[1,2],[3,4]],0) -> [1,3]\njStat.cola = function cola(arr, i) {\n return jStat.col(arr, i).map(function(a){ return a[0] });\n};\n\n\n// Returns the diagonal of the matrix\njStat.diag = function diag(arr) {\n var nrow = jStat.rows(arr);\n var res = new Array(nrow);\n for (var row = 0; row < nrow; row++)\n res[row] = [arr[row][row]];\n return res;\n};\n\n\n// Returns the anti-diagonal of the matrix\njStat.antidiag = function antidiag(arr) {\n var nrow = jStat.rows(arr) - 1;\n var res = new Array(nrow);\n for (var i = 0; nrow >= 0; nrow--, i++)\n res[i] = [arr[i][nrow]];\n return res;\n};\n\n// Transpose a matrix or array.\njStat.transpose = function transpose(arr) {\n var obj = [];\n var objArr, rows, cols, j, i;\n\n // Make sure arr is in matrix format.\n if (!isArray(arr[0]))\n arr = [arr];\n\n rows = arr.length;\n cols = arr[0].length;\n\n for (i = 0; i < cols; i++) {\n objArr = new Array(rows);\n for (j = 0; j < rows; j++)\n objArr[j] = arr[j][i];\n obj.push(objArr);\n }\n\n // If obj is vector, return only single array.\n return obj.length === 1 ? obj[0] : obj;\n};\n\n\n// Map a function to an array or array of arrays.\n// \"toAlter\" is an internal variable.\njStat.map = function map(arr, func, toAlter) {\n var row, nrow, ncol, res, col;\n\n if (!isArray(arr[0]))\n arr = [arr];\n\n nrow = arr.length;\n ncol = arr[0].length;\n res = toAlter ? arr : new Array(nrow);\n\n for (row = 0; row < nrow; row++) {\n // if the row doesn't exist, create it\n if (!res[row])\n res[row] = new Array(ncol);\n for (col = 0; col < ncol; col++)\n res[row][col] = func(arr[row][col], row, col);\n }\n\n return res.length === 1 ? res[0] : res;\n};\n\n\n// Cumulatively combine the elements of an array or array of arrays using a function.\njStat.cumreduce = function cumreduce(arr, func, toAlter) {\n var row, nrow, ncol, res, col;\n\n if (!isArray(arr[0]))\n arr = [arr];\n\n nrow = arr.length;\n ncol = arr[0].length;\n res = toAlter ? arr : new Array(nrow);\n\n for (row = 0; row < nrow; row++) {\n // if the row doesn't exist, create it\n if (!res[row])\n res[row] = new Array(ncol);\n if (ncol > 0)\n res[row][0] = arr[row][0];\n for (col = 1; col < ncol; col++)\n res[row][col] = func(res[row][col-1], arr[row][col]);\n }\n return res.length === 1 ? res[0] : res;\n};\n\n\n// Destructively alter an array.\njStat.alter = function alter(arr, func) {\n return jStat.map(arr, func, true);\n};\n\n\n// Generate a rows x cols matrix according to the supplied function.\njStat.create = function create(rows, cols, func) {\n var res = new Array(rows);\n var i, j;\n\n if (isFunction(cols)) {\n func = cols;\n cols = rows;\n }\n\n for (i = 0; i < rows; i++) {\n res[i] = new Array(cols);\n for (j = 0; j < cols; j++)\n res[i][j] = func(i, j);\n }\n\n return res;\n};\n\n\nfunction retZero() { return 0; }\n\n\n// Generate a rows x cols matrix of zeros.\njStat.zeros = function zeros(rows, cols) {\n if (!isNumber(cols))\n cols = rows;\n return jStat.create(rows, cols, retZero);\n};\n\n\nfunction retOne() { return 1; }\n\n\n// Generate a rows x cols matrix of ones.\njStat.ones = function ones(rows, cols) {\n if (!isNumber(cols))\n cols = rows;\n return jStat.create(rows, cols, retOne);\n};\n\n\n// Generate a rows x cols matrix of uniformly random numbers.\njStat.rand = function rand(rows, cols) {\n if (!isNumber(cols))\n cols = rows;\n return jStat.create(rows, cols, jStat._random_fn);\n};\n\n\nfunction retIdent(i, j) { return i === j ? 1 : 0; }\n\n\n// Generate an identity matrix of size row x cols.\njStat.identity = function identity(rows, cols) {\n if (!isNumber(cols))\n cols = rows;\n return jStat.create(rows, cols, retIdent);\n};\n\n\n// Tests whether a matrix is symmetric\njStat.symmetric = function symmetric(arr) {\n var size = arr.length;\n var row, col;\n\n if (arr.length !== arr[0].length)\n return false;\n\n for (row = 0; row < size; row++) {\n for (col = 0; col < size; col++)\n if (arr[col][row] !== arr[row][col])\n return false;\n }\n\n return true;\n};\n\n\n// Set all values to zero.\njStat.clear = function clear(arr) {\n return jStat.alter(arr, retZero);\n};\n\n\n// Generate sequence.\njStat.seq = function seq(min, max, length, func) {\n if (!isFunction(func))\n func = false;\n\n var arr = [];\n var hival = calcRdx(min, max);\n var step = (max * hival - min * hival) / ((length - 1) * hival);\n var current = min;\n var cnt;\n\n // Current is assigned using a technique to compensate for IEEE error.\n // TODO: Needs better implementation.\n for (cnt = 0;\n current <= max && cnt < length;\n cnt++, current = (min * hival + step * hival * cnt) / hival) {\n arr.push((func ? func(current, cnt) : current));\n }\n\n return arr;\n};\n\n\n// arange(5) -> [0,1,2,3,4]\n// arange(1,5) -> [1,2,3,4]\n// arange(5,1,-1) -> [5,4,3,2]\njStat.arange = function arange(start, end, step) {\n var rl = [];\n var i;\n step = step || 1;\n if (end === undefined) {\n end = start;\n start = 0;\n }\n if (start === end || step === 0) {\n return [];\n }\n if (start < end && step < 0) {\n return [];\n }\n if (start > end && step > 0) {\n return [];\n }\n if (step > 0) {\n for (i = start; i < end; i += step) {\n rl.push(i);\n }\n } else {\n for (i = start; i > end; i += step) {\n rl.push(i);\n }\n }\n return rl;\n};\n\n\n// A=[[1,2,3],[4,5,6],[7,8,9]]\n// slice(A,{row:{end:2},col:{start:1}}) -> [[2,3],[5,6]]\n// slice(A,1,{start:1}) -> [5,6]\n// as numpy code A[:2,1:]\njStat.slice = (function(){\n function _slice(list, start, end, step) {\n // note it's not equal to range.map mode it's a bug\n var i;\n var rl = [];\n var length = list.length;\n if (start === undefined && end === undefined && step === undefined) {\n return jStat.copy(list);\n }\n\n start = start || 0;\n end = end || list.length;\n start = start >= 0 ? start : length + start;\n end = end >= 0 ? end : length + end;\n step = step || 1;\n if (start === end || step === 0) {\n return [];\n }\n if (start < end && step < 0) {\n return [];\n }\n if (start > end && step > 0) {\n return [];\n }\n if (step > 0) {\n for (i = start; i < end; i += step) {\n rl.push(list[i]);\n }\n } else {\n for (i = start; i > end;i += step) {\n rl.push(list[i]);\n }\n }\n return rl;\n }\n\n function slice(list, rcSlice) {\n var colSlice, rowSlice;\n rcSlice = rcSlice || {};\n if (isNumber(rcSlice.row)) {\n if (isNumber(rcSlice.col))\n return list[rcSlice.row][rcSlice.col];\n var row = jStat.rowa(list, rcSlice.row);\n colSlice = rcSlice.col || {};\n return _slice(row, colSlice.start, colSlice.end, colSlice.step);\n }\n\n if (isNumber(rcSlice.col)) {\n var col = jStat.cola(list, rcSlice.col);\n rowSlice = rcSlice.row || {};\n return _slice(col, rowSlice.start, rowSlice.end, rowSlice.step);\n }\n\n rowSlice = rcSlice.row || {};\n colSlice = rcSlice.col || {};\n var rows = _slice(list, rowSlice.start, rowSlice.end, rowSlice.step);\n return rows.map(function(row) {\n return _slice(row, colSlice.start, colSlice.end, colSlice.step);\n });\n }\n\n return slice;\n}());\n\n\n// A=[[1,2,3],[4,5,6],[7,8,9]]\n// sliceAssign(A,{row:{start:1},col:{start:1}},[[0,0],[0,0]])\n// A=[[1,2,3],[4,0,0],[7,0,0]]\njStat.sliceAssign = function sliceAssign(A, rcSlice, B) {\n var nl, ml;\n if (isNumber(rcSlice.row)) {\n if (isNumber(rcSlice.col))\n return A[rcSlice.row][rcSlice.col] = B;\n rcSlice.col = rcSlice.col || {};\n rcSlice.col.start = rcSlice.col.start || 0;\n rcSlice.col.end = rcSlice.col.end || A[0].length;\n rcSlice.col.step = rcSlice.col.step || 1;\n nl = jStat.arange(rcSlice.col.start,\n Math.min(A.length, rcSlice.col.end),\n rcSlice.col.step);\n var m = rcSlice.row;\n nl.forEach(function(n, i) {\n A[m][n] = B[i];\n });\n return A;\n }\n\n if (isNumber(rcSlice.col)) {\n rcSlice.row = rcSlice.row || {};\n rcSlice.row.start = rcSlice.row.start || 0;\n rcSlice.row.end = rcSlice.row.end || A.length;\n rcSlice.row.step = rcSlice.row.step || 1;\n ml = jStat.arange(rcSlice.row.start,\n Math.min(A[0].length, rcSlice.row.end),\n rcSlice.row.step);\n var n = rcSlice.col;\n ml.forEach(function(m, j) {\n A[m][n] = B[j];\n });\n return A;\n }\n\n if (B[0].length === undefined) {\n B = [B];\n }\n rcSlice.row.start = rcSlice.row.start || 0;\n rcSlice.row.end = rcSlice.row.end || A.length;\n rcSlice.row.step = rcSlice.row.step || 1;\n rcSlice.col.start = rcSlice.col.start || 0;\n rcSlice.col.end = rcSlice.col.end || A[0].length;\n rcSlice.col.step = rcSlice.col.step || 1;\n ml = jStat.arange(rcSlice.row.start,\n Math.min(A.length, rcSlice.row.end),\n rcSlice.row.step);\n nl = jStat.arange(rcSlice.col.start,\n Math.min(A[0].length, rcSlice.col.end),\n rcSlice.col.step);\n ml.forEach(function(m, i) {\n nl.forEach(function(n, j) {\n A[m][n] = B[i][j];\n });\n });\n return A;\n};\n\n\n// [1,2,3] ->\n// [[1,0,0],[0,2,0],[0,0,3]]\njStat.diagonal = function diagonal(diagArray) {\n var mat = jStat.zeros(diagArray.length, diagArray.length);\n diagArray.forEach(function(t, i) {\n mat[i][i] = t;\n });\n return mat;\n};\n\n\n// return copy of A\njStat.copy = function copy(A) {\n return A.map(function(row) {\n if (isNumber(row))\n return row;\n return row.map(function(t) {\n return t;\n });\n });\n};\n\n\n// TODO: Go over this entire implementation. Seems a tragic waste of resources\n// doing all this work. Instead, and while ugly, use new Function() to generate\n// a custom function for each static method.\n\n// Quick reference.\nvar jProto = jStat.prototype;\n\n// Default length.\njProto.length = 0;\n\n// For internal use only.\n// TODO: Check if they're actually used, and if they are then rename them\n// to _*\njProto.push = Array.prototype.push;\njProto.sort = Array.prototype.sort;\njProto.splice = Array.prototype.splice;\njProto.slice = Array.prototype.slice;\n\n\n// Return a clean array.\njProto.toArray = function toArray() {\n return this.length > 1 ? slice.call(this) : slice.call(this)[0];\n};\n\n\n// Map a function to a matrix or vector.\njProto.map = function map(func, toAlter) {\n return jStat(jStat.map(this, func, toAlter));\n};\n\n\n// Cumulatively combine the elements of a matrix or vector using a function.\njProto.cumreduce = function cumreduce(func, toAlter) {\n return jStat(jStat.cumreduce(this, func, toAlter));\n};\n\n\n// Destructively alter an array.\njProto.alter = function alter(func) {\n jStat.alter(this, func);\n return this;\n};\n\n\n// Extend prototype with methods that have no argument.\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jProto[passfunc] = function(func) {\n var self = this,\n results;\n // Check for callback.\n if (func) {\n setTimeout(function() {\n func.call(self, jProto[passfunc].call(self));\n });\n return this;\n }\n results = jStat[passfunc](this);\n return isArray(results) ? jStat(results) : results;\n };\n })(funcs[i]);\n})('transpose clear symmetric rows cols dimensions diag antidiag'.split(' '));\n\n\n// Extend prototype with methods that have one argument.\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jProto[passfunc] = function(index, func) {\n var self = this;\n // check for callback\n if (func) {\n setTimeout(function() {\n func.call(self, jProto[passfunc].call(self, index));\n });\n return this;\n }\n return jStat(jStat[passfunc](this, index));\n };\n })(funcs[i]);\n})('row col'.split(' '));\n\n\n// Extend prototype with simple shortcut methods.\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jProto[passfunc] = function() {\n return jStat(jStat[passfunc].apply(null, arguments));\n };\n })(funcs[i]);\n})('create zeros ones rand identity'.split(' '));\n\n\n// Exposing jStat.\nreturn jStat;\n\n}(Math));\n(function(jStat, Math) {\n\nvar isFunction = jStat.utils.isFunction;\n\n// Ascending functions for sort\nfunction ascNum(a, b) { return a - b; }\n\nfunction clip(arg, min, max) {\n return Math.max(min, Math.min(arg, max));\n}\n\n\n// sum of an array\njStat.sum = function sum(arr) {\n var sum = 0;\n var i = arr.length;\n while (--i >= 0)\n sum += arr[i];\n return sum;\n};\n\n\n// sum squared\njStat.sumsqrd = function sumsqrd(arr) {\n var sum = 0;\n var i = arr.length;\n while (--i >= 0)\n sum += arr[i] * arr[i];\n return sum;\n};\n\n\n// sum of squared errors of prediction (SSE)\njStat.sumsqerr = function sumsqerr(arr) {\n var mean = jStat.mean(arr);\n var sum = 0;\n var i = arr.length;\n var tmp;\n while (--i >= 0) {\n tmp = arr[i] - mean;\n sum += tmp * tmp;\n }\n return sum;\n};\n\n// sum of an array in each row\njStat.sumrow = function sumrow(arr) {\n var sum = 0;\n var i = arr.length;\n while (--i >= 0)\n sum += arr[i];\n return sum;\n};\n\n// product of an array\njStat.product = function product(arr) {\n var prod = 1;\n var i = arr.length;\n while (--i >= 0)\n prod *= arr[i];\n return prod;\n};\n\n\n// minimum value of an array\njStat.min = function min(arr) {\n var low = arr[0];\n var i = 0;\n while (++i < arr.length)\n if (arr[i] < low)\n low = arr[i];\n return low;\n};\n\n\n// maximum value of an array\njStat.max = function max(arr) {\n var high = arr[0];\n var i = 0;\n while (++i < arr.length)\n if (arr[i] > high)\n high = arr[i];\n return high;\n};\n\n\n// unique values of an array\njStat.unique = function unique(arr) {\n var hash = {}, _arr = [];\n for(var i = 0; i < arr.length; i++) {\n if (!hash[arr[i]]) {\n hash[arr[i]] = true;\n _arr.push(arr[i]);\n }\n }\n return _arr;\n};\n\n\n// mean value of an array\njStat.mean = function mean(arr) {\n return jStat.sum(arr) / arr.length;\n};\n\n\n// mean squared error (MSE)\njStat.meansqerr = function meansqerr(arr) {\n return jStat.sumsqerr(arr) / arr.length;\n};\n\n\n// geometric mean of an array\njStat.geomean = function geomean(arr) {\n var logs = arr.map(Math.log)\n var meanOfLogs = jStat.mean(logs)\n return Math.exp(meanOfLogs)\n};\n\n\n// median of an array\njStat.median = function median(arr) {\n var arrlen = arr.length;\n var _arr = arr.slice().sort(ascNum);\n // check if array is even or odd, then return the appropriate\n return !(arrlen & 1)\n ? (_arr[(arrlen / 2) - 1 ] + _arr[(arrlen / 2)]) / 2\n : _arr[(arrlen / 2) | 0 ];\n};\n\n\n// cumulative sum of an array\njStat.cumsum = function cumsum(arr) {\n return jStat.cumreduce(arr, function (a, b) { return a + b; });\n};\n\n\n// cumulative product of an array\njStat.cumprod = function cumprod(arr) {\n return jStat.cumreduce(arr, function (a, b) { return a * b; });\n};\n\n\n// successive differences of a sequence\njStat.diff = function diff(arr) {\n var diffs = [];\n var arrLen = arr.length;\n var i;\n for (i = 1; i < arrLen; i++)\n diffs.push(arr[i] - arr[i - 1]);\n return diffs;\n};\n\n\n// ranks of an array\njStat.rank = function (arr) {\n var i;\n var distinctNumbers = [];\n var numberCounts = {};\n for (i = 0; i < arr.length; i++) {\n var number = arr[i];\n if (numberCounts[number]) {\n numberCounts[number]++;\n } else {\n numberCounts[number] = 1;\n distinctNumbers.push(number);\n }\n }\n\n var sortedDistinctNumbers = distinctNumbers.sort(ascNum);\n var numberRanks = {};\n var currentRank = 1;\n for (i = 0; i < sortedDistinctNumbers.length; i++) {\n var number = sortedDistinctNumbers[i];\n var count = numberCounts[number];\n var first = currentRank;\n var last = currentRank + count - 1;\n var rank = (first + last) / 2;\n numberRanks[number] = rank;\n currentRank += count;\n }\n\n return arr.map(function (number) {\n return numberRanks[number];\n });\n};\n\n\n// mode of an array\n// if there are multiple modes of an array, return all of them\n// is this the appropriate way of handling it?\njStat.mode = function mode(arr) {\n var arrLen = arr.length;\n var _arr = arr.slice().sort(ascNum);\n var count = 1;\n var maxCount = 0;\n var numMaxCount = 0;\n var mode_arr = [];\n var i;\n\n for (i = 0; i < arrLen; i++) {\n if (_arr[i] === _arr[i + 1]) {\n count++;\n } else {\n if (count > maxCount) {\n mode_arr = [_arr[i]];\n maxCount = count;\n numMaxCount = 0;\n }\n // are there multiple max counts\n else if (count === maxCount) {\n mode_arr.push(_arr[i]);\n numMaxCount++;\n }\n // resetting count for new value in array\n count = 1;\n }\n }\n\n return numMaxCount === 0 ? mode_arr[0] : mode_arr;\n};\n\n\n// range of an array\njStat.range = function range(arr) {\n return jStat.max(arr) - jStat.min(arr);\n};\n\n// variance of an array\n// flag = true indicates sample instead of population\njStat.variance = function variance(arr, flag) {\n return jStat.sumsqerr(arr) / (arr.length - (flag ? 1 : 0));\n};\n\n// pooled variance of an array of arrays\njStat.pooledvariance = function pooledvariance(arr) {\n var sumsqerr = arr.reduce(function (a, samples) {return a + jStat.sumsqerr(samples);}, 0);\n var count = arr.reduce(function (a, samples) {return a + samples.length;}, 0);\n return sumsqerr / (count - arr.length);\n};\n\n// deviation of an array\njStat.deviation = function (arr) {\n var mean = jStat.mean(arr);\n var arrlen = arr.length;\n var dev = new Array(arrlen);\n for (var i = 0; i < arrlen; i++) {\n dev[i] = arr[i] - mean;\n }\n return dev;\n};\n\n// standard deviation of an array\n// flag = true indicates sample instead of population\njStat.stdev = function stdev(arr, flag) {\n return Math.sqrt(jStat.variance(arr, flag));\n};\n\n// pooled standard deviation of an array of arrays\njStat.pooledstdev = function pooledstdev(arr) {\n return Math.sqrt(jStat.pooledvariance(arr));\n};\n\n// mean deviation (mean absolute deviation) of an array\njStat.meandev = function meandev(arr) {\n var mean = jStat.mean(arr);\n var a = [];\n for (var i = arr.length - 1; i >= 0; i--) {\n a.push(Math.abs(arr[i] - mean));\n }\n return jStat.mean(a);\n};\n\n\n// median deviation (median absolute deviation) of an array\njStat.meddev = function meddev(arr) {\n var median = jStat.median(arr);\n var a = [];\n for (var i = arr.length - 1; i >= 0; i--) {\n a.push(Math.abs(arr[i] - median));\n }\n return jStat.median(a);\n};\n\n\n// coefficient of variation\njStat.coeffvar = function coeffvar(arr) {\n return jStat.stdev(arr) / jStat.mean(arr);\n};\n\n\n// quartiles of an array\njStat.quartiles = function quartiles(arr) {\n var arrlen = arr.length;\n var _arr = arr.slice().sort(ascNum);\n return [\n _arr[ Math.round((arrlen) / 4) - 1 ],\n _arr[ Math.round((arrlen) / 2) - 1 ],\n _arr[ Math.round((arrlen) * 3 / 4) - 1 ]\n ];\n};\n\n\n// Arbitary quantiles of an array. Direct port of the scipy.stats\n// implementation by Pierre GF Gerard-Marchant.\njStat.quantiles = function quantiles(arr, quantilesArray, alphap, betap) {\n var sortedArray = arr.slice().sort(ascNum);\n var quantileVals = [quantilesArray.length];\n var n = arr.length;\n var i, p, m, aleph, k, gamma;\n\n if (typeof alphap === 'undefined')\n alphap = 3 / 8;\n if (typeof betap === 'undefined')\n betap = 3 / 8;\n\n for (i = 0; i < quantilesArray.length; i++) {\n p = quantilesArray[i];\n m = alphap + p * (1 - alphap - betap);\n aleph = n * p + m;\n k = Math.floor(clip(aleph, 1, n - 1));\n gamma = clip(aleph - k, 0, 1);\n quantileVals[i] = (1 - gamma) * sortedArray[k - 1] + gamma * sortedArray[k];\n }\n\n return quantileVals;\n};\n\n// Return the k-th percentile of values in a range, where k is in the range 0..1, inclusive.\n// Passing true for the exclusive parameter excludes both endpoints of the range.\njStat.percentile = function percentile(arr, k, exclusive) {\n var _arr = arr.slice().sort(ascNum);\n var realIndex = k * (_arr.length + (exclusive ? 1 : -1)) + (exclusive ? 0 : 1);\n var index = parseInt(realIndex);\n var frac = realIndex - index;\n if (index + 1 < _arr.length) {\n return _arr[index - 1] + frac * (_arr[index] - _arr[index - 1]);\n } else {\n return _arr[index - 1];\n }\n}\n\n// The percentile rank of score in a given array. Returns the percentage\n// of all values in the input array that are less than (kind='strict') or\n// less or equal than (kind='weak') score. Default is weak.\njStat.percentileOfScore = function percentileOfScore(arr, score, kind) {\n var counter = 0;\n var len = arr.length;\n var strict = false;\n var value, i;\n\n if (kind === 'strict')\n strict = true;\n\n for (i = 0; i < len; i++) {\n value = arr[i];\n if ((strict && value < score) ||\n (!strict && value <= score)) {\n counter++;\n }\n }\n\n return counter / len;\n};\n\n\n// Histogram (bin count) data\njStat.histogram = function histogram(arr, binCnt) {\n binCnt = binCnt || 4;\n var first = jStat.min(arr);\n var binWidth = (jStat.max(arr) - first) / binCnt;\n var len = arr.length;\n var bins = [];\n var i;\n\n for (i = 0; i < binCnt; i++)\n bins[i] = 0;\n for (i = 0; i < len; i++)\n bins[Math.min(Math.floor(((arr[i] - first) / binWidth)), binCnt - 1)] += 1;\n\n return bins;\n};\n\n\n// covariance of two arrays\njStat.covariance = function covariance(arr1, arr2) {\n var u = jStat.mean(arr1);\n var v = jStat.mean(arr2);\n var arr1Len = arr1.length;\n var sq_dev = new Array(arr1Len);\n var i;\n\n for (i = 0; i < arr1Len; i++)\n sq_dev[i] = (arr1[i] - u) * (arr2[i] - v);\n\n return jStat.sum(sq_dev) / (arr1Len - 1);\n};\n\n\n// (pearson's) population correlation coefficient, rho\njStat.corrcoeff = function corrcoeff(arr1, arr2) {\n return jStat.covariance(arr1, arr2) /\n jStat.stdev(arr1, 1) /\n jStat.stdev(arr2, 1);\n};\n\n // (spearman's) rank correlation coefficient, sp\njStat.spearmancoeff = function (arr1, arr2) {\n arr1 = jStat.rank(arr1);\n arr2 = jStat.rank(arr2);\n //return pearson's correlation of the ranks:\n return jStat.corrcoeff(arr1, arr2);\n}\n\n\n// statistical standardized moments (general form of skew/kurt)\njStat.stanMoment = function stanMoment(arr, n) {\n var mu = jStat.mean(arr);\n var sigma = jStat.stdev(arr);\n var len = arr.length;\n var skewSum = 0;\n\n for (var i = 0; i < len; i++)\n skewSum += Math.pow((arr[i] - mu) / sigma, n);\n\n return skewSum / arr.length;\n};\n\n// (pearson's) moment coefficient of skewness\njStat.skewness = function skewness(arr) {\n return jStat.stanMoment(arr, 3);\n};\n\n// (pearson's) (excess) kurtosis\njStat.kurtosis = function kurtosis(arr) {\n return jStat.stanMoment(arr, 4) - 3;\n};\n\n\nvar jProto = jStat.prototype;\n\n\n// Extend jProto with method for calculating cumulative sums and products.\n// This differs from the similar extension below as cumsum and cumprod should\n// not be run again in the case fullbool === true.\n// If a matrix is passed, automatically assume operation should be done on the\n// columns.\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n // If a matrix is passed, automatically assume operation should be done on\n // the columns.\n jProto[passfunc] = function(fullbool, func) {\n var arr = [];\n var i = 0;\n var tmpthis = this;\n // Assignment reassignation depending on how parameters were passed in.\n if (isFunction(fullbool)) {\n func = fullbool;\n fullbool = false;\n }\n // Check if a callback was passed with the function.\n if (func) {\n setTimeout(function() {\n func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool));\n });\n return this;\n }\n // Check if matrix and run calculations.\n if (this.length > 1) {\n tmpthis = fullbool === true ? this : this.transpose();\n for (; i < tmpthis.length; i++)\n arr[i] = jStat[passfunc](tmpthis[i]);\n return arr;\n }\n // Pass fullbool if only vector, not a matrix. for variance and stdev.\n return jStat[passfunc](this[0], fullbool);\n };\n })(funcs[i]);\n})(('cumsum cumprod').split(' '));\n\n\n// Extend jProto with methods which don't require arguments and work on columns.\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n // If a matrix is passed, automatically assume operation should be done on\n // the columns.\n jProto[passfunc] = function(fullbool, func) {\n var arr = [];\n var i = 0;\n var tmpthis = this;\n // Assignment reassignation depending on how parameters were passed in.\n if (isFunction(fullbool)) {\n func = fullbool;\n fullbool = false;\n }\n // Check if a callback was passed with the function.\n if (func) {\n setTimeout(function() {\n func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool));\n });\n return this;\n }\n // Check if matrix and run calculations.\n if (this.length > 1) {\n if (passfunc !== 'sumrow')\n tmpthis = fullbool === true ? this : this.transpose();\n for (; i < tmpthis.length; i++)\n arr[i] = jStat[passfunc](tmpthis[i]);\n return fullbool === true\n ? jStat[passfunc](jStat.utils.toVector(arr))\n : arr;\n }\n // Pass fullbool if only vector, not a matrix. for variance and stdev.\n return jStat[passfunc](this[0], fullbool);\n };\n })(funcs[i]);\n})(('sum sumsqrd sumsqerr sumrow product min max unique mean meansqerr ' +\n 'geomean median diff rank mode range variance deviation stdev meandev ' +\n 'meddev coeffvar quartiles histogram skewness kurtosis').split(' '));\n\n\n// Extend jProto with functions that take arguments. Operations on matrices are\n// done on columns.\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jProto[passfunc] = function() {\n var arr = [];\n var i = 0;\n var tmpthis = this;\n var args = Array.prototype.slice.call(arguments);\n var callbackFunction;\n\n // If the last argument is a function, we assume it's a callback; we\n // strip the callback out and call the function again.\n if (isFunction(args[args.length - 1])) {\n callbackFunction = args[args.length - 1];\n var argsToPass = args.slice(0, args.length - 1);\n\n setTimeout(function() {\n callbackFunction.call(tmpthis,\n jProto[passfunc].apply(tmpthis, argsToPass));\n });\n return this;\n\n // Otherwise we curry the function args and call normally.\n } else {\n callbackFunction = undefined;\n var curriedFunction = function curriedFunction(vector) {\n return jStat[passfunc].apply(tmpthis, [vector].concat(args));\n }\n }\n\n // If this is a matrix, run column-by-column.\n if (this.length > 1) {\n tmpthis = tmpthis.transpose();\n for (; i < tmpthis.length; i++)\n arr[i] = curriedFunction(tmpthis[i]);\n return arr;\n }\n\n // Otherwise run on the vector.\n return curriedFunction(this[0]);\n };\n })(funcs[i]);\n})('quantiles percentileOfScore'.split(' '));\n\n}(jStat, Math));\n// Special functions //\n(function(jStat, Math) {\n\n// Log-gamma function\njStat.gammaln = function gammaln(x) {\n var j = 0;\n var cof = [\n 76.18009172947146, -86.50532032941677, 24.01409824083091,\n -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5\n ];\n var ser = 1.000000000190015;\n var xx, y, tmp;\n tmp = (y = xx = x) + 5.5;\n tmp -= (xx + 0.5) * Math.log(tmp);\n for (; j < 6; j++)\n ser += cof[j] / ++y;\n return Math.log(2.5066282746310005 * ser / xx) - tmp;\n};\n\n/*\n * log-gamma function to support poisson distribution sampling. The\n * algorithm comes from SPECFUN by Shanjie Zhang and Jianming Jin and their\n * book \"Computation of Special Functions\", 1996, John Wiley & Sons, Inc.\n */\njStat.loggam = function loggam(x) {\n var x0, x2, xp, gl, gl0;\n var k, n;\n\n var a = [8.333333333333333e-02, -2.777777777777778e-03,\n 7.936507936507937e-04, -5.952380952380952e-04,\n 8.417508417508418e-04, -1.917526917526918e-03,\n 6.410256410256410e-03, -2.955065359477124e-02,\n 1.796443723688307e-01, -1.39243221690590e+00];\n x0 = x;\n n = 0;\n if ((x == 1.0) || (x == 2.0)) {\n return 0.0;\n }\n if (x <= 7.0) {\n n = Math.floor(7 - x);\n x0 = x + n;\n }\n x2 = 1.0 / (x0 * x0);\n xp = 2 * Math.PI;\n gl0 = a[9];\n for (k = 8; k >= 0; k--) {\n gl0 *= x2;\n gl0 += a[k];\n }\n gl = gl0 / x0 + 0.5 * Math.log(xp) + (x0 - 0.5) * Math.log(x0) - x0;\n if (x <= 7.0) {\n for (k = 1; k <= n; k++) {\n gl -= Math.log(x0 - 1.0);\n x0 -= 1.0;\n }\n }\n return gl;\n}\n\n// gamma of x\njStat.gammafn = function gammafn(x) {\n var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563,\n 629.3311553128184, 866.9662027904133, -31451.272968848367,\n -36144.413418691176, 66456.14382024054\n ];\n var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192,\n -3107.771671572311, 22538.118420980151, 4755.8462775278811,\n -134659.9598649693, -115132.2596755535];\n var fact = false;\n var n = 0;\n var xden = 0;\n var xnum = 0;\n var y = x;\n var i, z, yi, res;\n if (x > 171.6243769536076) {\n return Infinity;\n }\n if (y <= 0) {\n res = y % 1 + 3.6e-16;\n if (res) {\n fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res);\n y = 1 - y;\n } else {\n return Infinity;\n }\n }\n yi = y;\n if (y < 1) {\n z = y++;\n } else {\n z = (y -= n = (y | 0) - 1) - 1;\n }\n for (i = 0; i < 8; ++i) {\n xnum = (xnum + p[i]) * z;\n xden = xden * z + q[i];\n }\n res = xnum / xden + 1;\n if (yi < y) {\n res /= yi;\n } else if (yi > y) {\n for (i = 0; i < n; ++i) {\n res *= y;\n y++;\n }\n }\n if (fact) {\n res = fact / res;\n }\n return res;\n};\n\n\n// lower incomplete gamma function, which is usually typeset with a\n// lower-case greek gamma as the function symbol\njStat.gammap = function gammap(a, x) {\n return jStat.lowRegGamma(a, x) * jStat.gammafn(a);\n};\n\n\n// The lower regularized incomplete gamma function, usually written P(a,x)\njStat.lowRegGamma = function lowRegGamma(a, x) {\n var aln = jStat.gammaln(a);\n var ap = a;\n var sum = 1 / a;\n var del = sum;\n var b = x + 1 - a;\n var c = 1 / 1.0e-30;\n var d = 1 / b;\n var h = d;\n var i = 1;\n // calculate maximum number of itterations required for a\n var ITMAX = -~(Math.log((a >= 1) ? a : 1 / a) * 8.5 + a * 0.4 + 17);\n var an;\n\n if (x < 0 || a <= 0) {\n return NaN;\n } else if (x < a + 1) {\n for (; i <= ITMAX; i++) {\n sum += del *= x / ++ap;\n }\n return (sum * Math.exp(-x + a * Math.log(x) - (aln)));\n }\n\n for (; i <= ITMAX; i++) {\n an = -i * (i - a);\n b += 2;\n d = an * d + b;\n c = b + an / c;\n d = 1 / d;\n h *= d * c;\n }\n\n return (1 - h * Math.exp(-x + a * Math.log(x) - (aln)));\n};\n\n// natural log factorial of n\njStat.factorialln = function factorialln(n) {\n return n < 0 ? NaN : jStat.gammaln(n + 1);\n};\n\n// factorial of n\njStat.factorial = function factorial(n) {\n return n < 0 ? NaN : jStat.gammafn(n + 1);\n};\n\n// combinations of n, m\njStat.combination = function combination(n, m) {\n // make sure n or m don't exceed the upper limit of usable values\n return (n > 170 || m > 170)\n ? Math.exp(jStat.combinationln(n, m))\n : (jStat.factorial(n) / jStat.factorial(m)) / jStat.factorial(n - m);\n};\n\n\njStat.combinationln = function combinationln(n, m){\n return jStat.factorialln(n) - jStat.factorialln(m) - jStat.factorialln(n - m);\n};\n\n\n// permutations of n, m\njStat.permutation = function permutation(n, m) {\n return jStat.factorial(n) / jStat.factorial(n - m);\n};\n\n\n// beta function\njStat.betafn = function betafn(x, y) {\n // ensure arguments are positive\n if (x <= 0 || y <= 0)\n return undefined;\n // make sure x + y doesn't exceed the upper limit of usable values\n return (x + y > 170)\n ? Math.exp(jStat.betaln(x, y))\n : jStat.gammafn(x) * jStat.gammafn(y) / jStat.gammafn(x + y);\n};\n\n\n// natural logarithm of beta function\njStat.betaln = function betaln(x, y) {\n return jStat.gammaln(x) + jStat.gammaln(y) - jStat.gammaln(x + y);\n};\n\n\n// Evaluates the continued fraction for incomplete beta function by modified\n// Lentz's method.\njStat.betacf = function betacf(x, a, b) {\n var fpmin = 1e-30;\n var m = 1;\n var qab = a + b;\n var qap = a + 1;\n var qam = a - 1;\n var c = 1;\n var d = 1 - qab * x / qap;\n var m2, aa, del, h;\n\n // These q's will be used in factors that occur in the coefficients\n if (Math.abs(d) < fpmin)\n d = fpmin;\n d = 1 / d;\n h = d;\n\n for (; m <= 100; m++) {\n m2 = 2 * m;\n aa = m * (b - m) * x / ((qam + m2) * (a + m2));\n // One step (the even one) of the recurrence\n d = 1 + aa * d;\n if (Math.abs(d) < fpmin)\n d = fpmin;\n c = 1 + aa / c;\n if (Math.abs(c) < fpmin)\n c = fpmin;\n d = 1 / d;\n h *= d * c;\n aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));\n // Next step of the recurrence (the odd one)\n d = 1 + aa * d;\n if (Math.abs(d) < fpmin)\n d = fpmin;\n c = 1 + aa / c;\n if (Math.abs(c) < fpmin)\n c = fpmin;\n d = 1 / d;\n del = d * c;\n h *= del;\n if (Math.abs(del - 1.0) < 3e-7)\n break;\n }\n\n return h;\n};\n\n\n// Returns the inverse of the lower regularized inomplete gamma function\njStat.gammapinv = function gammapinv(p, a) {\n var j = 0;\n var a1 = a - 1;\n var EPS = 1e-8;\n var gln = jStat.gammaln(a);\n var x, err, t, u, pp, lna1, afac;\n\n if (p >= 1)\n return Math.max(100, a + 100 * Math.sqrt(a));\n if (p <= 0)\n return 0;\n if (a > 1) {\n lna1 = Math.log(a1);\n afac = Math.exp(a1 * (lna1 - 1) - gln);\n pp = (p < 0.5) ? p : 1 - p;\n t = Math.sqrt(-2 * Math.log(pp));\n x = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;\n if (p < 0.5)\n x = -x;\n x = Math.max(1e-3,\n a * Math.pow(1 - 1 / (9 * a) - x / (3 * Math.sqrt(a)), 3));\n } else {\n t = 1 - a * (0.253 + a * 0.12);\n if (p < t)\n x = Math.pow(p / t, 1 / a);\n else\n x = 1 - Math.log(1 - (p - t) / (1 - t));\n }\n\n for(; j < 12; j++) {\n if (x <= 0)\n return 0;\n err = jStat.lowRegGamma(a, x) - p;\n if (a > 1)\n t = afac * Math.exp(-(x - a1) + a1 * (Math.log(x) - lna1));\n else\n t = Math.exp(-x + a1 * Math.log(x) - gln);\n u = err / t;\n x -= (t = u / (1 - 0.5 * Math.min(1, u * ((a - 1) / x - 1))));\n if (x <= 0)\n x = 0.5 * (x + t);\n if (Math.abs(t) < EPS * x)\n break;\n }\n\n return x;\n};\n\n\n// Returns the error function erf(x)\njStat.erf = function erf(x) {\n var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2,\n -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4,\n 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6,\n 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8,\n 6.529054439e-9, 5.059343495e-9, -9.91364156e-10,\n -2.27365122e-10, 9.6467911e-11, 2.394038e-12,\n -6.886027e-12, 8.94487e-13, 3.13092e-13,\n -1.12708e-13, 3.81e-16, 7.106e-15,\n -1.523e-15, -9.4e-17, 1.21e-16,\n -2.8e-17];\n var j = cof.length - 1;\n var isneg = false;\n var d = 0;\n var dd = 0;\n var t, ty, tmp, res;\n\n if (x < 0) {\n x = -x;\n isneg = true;\n }\n\n t = 2 / (2 + x);\n ty = 4 * t - 2;\n\n for(; j > 0; j--) {\n tmp = d;\n d = ty * d - dd + cof[j];\n dd = tmp;\n }\n\n res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd);\n return isneg ? res - 1 : 1 - res;\n};\n\n\n// Returns the complmentary error function erfc(x)\njStat.erfc = function erfc(x) {\n return 1 - jStat.erf(x);\n};\n\n\n// Returns the inverse of the complementary error function\njStat.erfcinv = function erfcinv(p) {\n var j = 0;\n var x, err, t, pp;\n if (p >= 2)\n return -100;\n if (p <= 0)\n return 100;\n pp = (p < 1) ? p : 2 - p;\n t = Math.sqrt(-2 * Math.log(pp / 2));\n x = -0.70711 * ((2.30753 + t * 0.27061) /\n (1 + t * (0.99229 + t * 0.04481)) - t);\n for (; j < 2; j++) {\n err = jStat.erfc(x) - pp;\n x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err);\n }\n return (p < 1) ? x : -x;\n};\n\n\n// Returns the inverse of the incomplete beta function\njStat.ibetainv = function ibetainv(p, a, b) {\n var EPS = 1e-8;\n var a1 = a - 1;\n var b1 = b - 1;\n var j = 0;\n var lna, lnb, pp, t, u, err, x, al, h, w, afac;\n if (p <= 0)\n return 0;\n if (p >= 1)\n return 1;\n if (a >= 1 && b >= 1) {\n pp = (p < 0.5) ? p : 1 - p;\n t = Math.sqrt(-2 * Math.log(pp));\n x = (2.30753 + t * 0.27061) / (1 + t* (0.99229 + t * 0.04481)) - t;\n if (p < 0.5)\n x = -x;\n al = (x * x - 3) / 6;\n h = 2 / (1 / (2 * a - 1) + 1 / (2 * b - 1));\n w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) *\n (al + 5 / 6 - 2 / (3 * h));\n x = a / (a + b * Math.exp(2 * w));\n } else {\n lna = Math.log(a / (a + b));\n lnb = Math.log(b / (a + b));\n t = Math.exp(a * lna) / a;\n u = Math.exp(b * lnb) / b;\n w = t + u;\n if (p < t / w)\n x = Math.pow(a * w * p, 1 / a);\n else\n x = 1 - Math.pow(b * w * (1 - p), 1 / b);\n }\n afac = -jStat.gammaln(a) - jStat.gammaln(b) + jStat.gammaln(a + b);\n for(; j < 10; j++) {\n if (x === 0 || x === 1)\n return x;\n err = jStat.ibeta(x, a, b) - p;\n t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac);\n u = err / t;\n x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x)))));\n if (x <= 0)\n x = 0.5 * (x + t);\n if (x >= 1)\n x = 0.5 * (x + t + 1);\n if (Math.abs(t) < EPS * x && j > 0)\n break;\n }\n return x;\n};\n\n\n// Returns the incomplete beta function I_x(a,b)\njStat.ibeta = function ibeta(x, a, b) {\n // Factors in front of the continued fraction.\n var bt = (x === 0 || x === 1) ? 0 :\n Math.exp(jStat.gammaln(a + b) - jStat.gammaln(a) -\n jStat.gammaln(b) + a * Math.log(x) + b *\n Math.log(1 - x));\n if (x < 0 || x > 1)\n return false;\n if (x < (a + 1) / (a + b + 2))\n // Use continued fraction directly.\n return bt * jStat.betacf(x, a, b) / a;\n // else use continued fraction after making the symmetry transformation.\n return 1 - bt * jStat.betacf(1 - x, b, a) / b;\n};\n\n\n// Returns a normal deviate (mu=0, sigma=1).\n// If n and m are specified it returns a object of normal deviates.\njStat.randn = function randn(n, m) {\n var u, v, x, y, q;\n if (!m)\n m = n;\n if (n)\n return jStat.create(n, m, function() { return jStat.randn(); });\n do {\n u = jStat._random_fn();\n v = 1.7156 * (jStat._random_fn() - 0.5);\n x = u - 0.449871;\n y = Math.abs(v) + 0.386595;\n q = x * x + y * (0.19600 * y - 0.25472 * x);\n } while (q > 0.27597 && (q > 0.27846 || v * v > -4 * Math.log(u) * u * u));\n return v / u;\n};\n\n\n// Returns a gamma deviate by the method of Marsaglia and Tsang.\njStat.randg = function randg(shape, n, m) {\n var oalph = shape;\n var a1, a2, u, v, x, mat;\n if (!m)\n m = n;\n if (!shape)\n shape = 1;\n if (n) {\n mat = jStat.zeros(n,m);\n mat.alter(function() { return jStat.randg(shape); });\n return mat;\n }\n if (shape < 1)\n shape += 1;\n a1 = shape - 1 / 3;\n a2 = 1 / Math.sqrt(9 * a1);\n do {\n do {\n x = jStat.randn();\n v = 1 + a2 * x;\n } while(v <= 0);\n v = v * v * v;\n u = jStat._random_fn();\n } while(u > 1 - 0.331 * Math.pow(x, 4) &&\n Math.log(u) > 0.5 * x*x + a1 * (1 - v + Math.log(v)));\n // alpha > 1\n if (shape == oalph)\n return a1 * v;\n // alpha < 1\n do {\n u = jStat._random_fn();\n } while(u === 0);\n return Math.pow(u, 1 / oalph) * a1 * v;\n};\n\n\n// making use of static methods on the instance\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jStat.fn[passfunc] = function() {\n return jStat(\n jStat.map(this, function(value) { return jStat[passfunc](value); }));\n }\n })(funcs[i]);\n})('gammaln gammafn factorial factorialln'.split(' '));\n\n\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jStat.fn[passfunc] = function() {\n return jStat(jStat[passfunc].apply(null, arguments));\n };\n })(funcs[i]);\n})('randn'.split(' '));\n\n}(jStat, Math));\n(function(jStat, Math) {\n\n// generate all distribution instance methods\n(function(list) {\n for (var i = 0; i < list.length; i++) (function(func) {\n // distribution instance method\n jStat[func] = function f(a, b, c) {\n if (!(this instanceof f))\n return new f(a, b, c);\n this._a = a;\n this._b = b;\n this._c = c;\n return this;\n };\n // distribution method to be used on a jStat instance\n jStat.fn[func] = function(a, b, c) {\n var newthis = jStat[func](a, b, c);\n newthis.data = this;\n return newthis;\n };\n // sample instance method\n jStat[func].prototype.sample = function(arr) {\n var a = this._a;\n var b = this._b;\n var c = this._c;\n if (arr)\n return jStat.alter(arr, function() {\n return jStat[func].sample(a, b, c);\n });\n else\n return jStat[func].sample(a, b, c);\n };\n // generate the pdf, cdf and inv instance methods\n (function(vals) {\n for (var i = 0; i < vals.length; i++) (function(fnfunc) {\n jStat[func].prototype[fnfunc] = function(x) {\n var a = this._a;\n var b = this._b;\n var c = this._c;\n if (!x && x !== 0)\n x = this.data;\n if (typeof x !== 'number') {\n return jStat.fn.map.call(x, function(x) {\n return jStat[func][fnfunc](x, a, b, c);\n });\n }\n return jStat[func][fnfunc](x, a, b, c);\n };\n })(vals[i]);\n })('pdf cdf inv'.split(' '));\n // generate the mean, median, mode and variance instance methods\n (function(vals) {\n for (var i = 0; i < vals.length; i++) (function(fnfunc) {\n jStat[func].prototype[fnfunc] = function() {\n return jStat[func][fnfunc](this._a, this._b, this._c);\n };\n })(vals[i]);\n })('mean median mode variance'.split(' '));\n })(list[i]);\n})((\n 'beta centralF cauchy chisquare exponential gamma invgamma kumaraswamy ' +\n 'laplace lognormal noncentralt normal pareto studentt weibull uniform ' +\n 'binomial negbin hypgeom poisson triangular tukey arcsine'\n).split(' '));\n\n\n\n// extend beta function with static methods\njStat.extend(jStat.beta, {\n pdf: function pdf(x, alpha, beta) {\n // PDF is zero outside the support\n if (x > 1 || x < 0)\n return 0;\n // PDF is one for the uniform case\n if (alpha == 1 && beta == 1)\n return 1;\n\n if (alpha < 512 && beta < 512) {\n return (Math.pow(x, alpha - 1) * Math.pow(1 - x, beta - 1)) /\n jStat.betafn(alpha, beta);\n } else {\n return Math.exp((alpha - 1) * Math.log(x) +\n (beta - 1) * Math.log(1 - x) -\n jStat.betaln(alpha, beta));\n }\n },\n\n cdf: function cdf(x, alpha, beta) {\n return (x > 1 || x < 0) ? (x > 1) * 1 : jStat.ibeta(x, alpha, beta);\n },\n\n inv: function inv(x, alpha, beta) {\n return jStat.ibetainv(x, alpha, beta);\n },\n\n mean: function mean(alpha, beta) {\n return alpha / (alpha + beta);\n },\n\n median: function median(alpha, beta) {\n return jStat.ibetainv(0.5, alpha, beta);\n },\n\n mode: function mode(alpha, beta) {\n return (alpha - 1 ) / ( alpha + beta - 2);\n },\n\n // return a random sample\n sample: function sample(alpha, beta) {\n var u = jStat.randg(alpha);\n return u / (u + jStat.randg(beta));\n },\n\n variance: function variance(alpha, beta) {\n return (alpha * beta) / (Math.pow(alpha + beta, 2) * (alpha + beta + 1));\n }\n});\n\n// extend F function with static methods\njStat.extend(jStat.centralF, {\n // This implementation of the pdf function avoids float overflow\n // See the way that R calculates this value:\n // https://svn.r-project.org/R/trunk/src/nmath/df.c\n pdf: function pdf(x, df1, df2) {\n var p, q, f;\n\n if (x < 0)\n return 0;\n\n if (df1 <= 2) {\n if (x === 0 && df1 < 2) {\n return Infinity;\n }\n if (x === 0 && df1 === 2) {\n return 1;\n }\n return (1 / jStat.betafn(df1 / 2, df2 / 2)) *\n Math.pow(df1 / df2, df1 / 2) *\n Math.pow(x, (df1/2) - 1) *\n Math.pow((1 + (df1 / df2) * x), -(df1 + df2) / 2);\n }\n\n p = (df1 * x) / (df2 + x * df1);\n q = df2 / (df2 + x * df1);\n f = df1 * q / 2.0;\n return f * jStat.binomial.pdf((df1 - 2) / 2, (df1 + df2 - 2) / 2, p);\n },\n\n cdf: function cdf(x, df1, df2) {\n if (x < 0)\n return 0;\n return jStat.ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2);\n },\n\n inv: function inv(x, df1, df2) {\n return df2 / (df1 * (1 / jStat.ibetainv(x, df1 / 2, df2 / 2) - 1));\n },\n\n mean: function mean(df1, df2) {\n return (df2 > 2) ? df2 / (df2 - 2) : undefined;\n },\n\n mode: function mode(df1, df2) {\n return (df1 > 2) ? (df2 * (df1 - 2)) / (df1 * (df2 + 2)) : undefined;\n },\n\n // return a random sample\n sample: function sample(df1, df2) {\n var x1 = jStat.randg(df1 / 2) * 2;\n var x2 = jStat.randg(df2 / 2) * 2;\n return (x1 / df1) / (x2 / df2);\n },\n\n variance: function variance(df1, df2) {\n if (df2 <= 4)\n return undefined;\n return 2 * df2 * df2 * (df1 + df2 - 2) /\n (df1 * (df2 - 2) * (df2 - 2) * (df2 - 4));\n }\n});\n\n\n// extend cauchy function with static methods\njStat.extend(jStat.cauchy, {\n pdf: function pdf(x, local, scale) {\n if (scale < 0) { return 0; }\n\n return (scale / (Math.pow(x - local, 2) + Math.pow(scale, 2))) / Math.PI;\n },\n\n cdf: function cdf(x, local, scale) {\n return Math.atan((x - local) / scale) / Math.PI + 0.5;\n },\n\n inv: function(p, local, scale) {\n return local + scale * Math.tan(Math.PI * (p - 0.5));\n },\n\n median: function median(local/*, scale*/) {\n return local;\n },\n\n mode: function mode(local/*, scale*/) {\n return local;\n },\n\n sample: function sample(local, scale) {\n return jStat.randn() *\n Math.sqrt(1 / (2 * jStat.randg(0.5))) * scale + local;\n }\n});\n\n\n\n// extend chisquare function with static methods\njStat.extend(jStat.chisquare, {\n pdf: function pdf(x, dof) {\n if (x < 0)\n return 0;\n return (x === 0 && dof === 2) ? 0.5 :\n Math.exp((dof / 2 - 1) * Math.log(x) - x / 2 - (dof / 2) *\n Math.log(2) - jStat.gammaln(dof / 2));\n },\n\n cdf: function cdf(x, dof) {\n if (x < 0)\n return 0;\n return jStat.lowRegGamma(dof / 2, x / 2);\n },\n\n inv: function(p, dof) {\n return 2 * jStat.gammapinv(p, 0.5 * dof);\n },\n\n mean : function(dof) {\n return dof;\n },\n\n // TODO: this is an approximation (is there a better way?)\n median: function median(dof) {\n return dof * Math.pow(1 - (2 / (9 * dof)), 3);\n },\n\n mode: function mode(dof) {\n return (dof - 2 > 0) ? dof - 2 : 0;\n },\n\n sample: function sample(dof) {\n return jStat.randg(dof / 2) * 2;\n },\n\n variance: function variance(dof) {\n return 2 * dof;\n }\n});\n\n\n\n// extend exponential function with static methods\njStat.extend(jStat.exponential, {\n pdf: function pdf(x, rate) {\n return x < 0 ? 0 : rate * Math.exp(-rate * x);\n },\n\n cdf: function cdf(x, rate) {\n return x < 0 ? 0 : 1 - Math.exp(-rate * x);\n },\n\n inv: function(p, rate) {\n return -Math.log(1 - p) / rate;\n },\n\n mean : function(rate) {\n return 1 / rate;\n },\n\n median: function (rate) {\n return (1 / rate) * Math.log(2);\n },\n\n mode: function mode(/*rate*/) {\n return 0;\n },\n\n sample: function sample(rate) {\n return -1 / rate * Math.log(jStat._random_fn());\n },\n\n variance : function(rate) {\n return Math.pow(rate, -2);\n }\n});\n\n\n\n// extend gamma function with static methods\njStat.extend(jStat.gamma, {\n pdf: function pdf(x, shape, scale) {\n if (x < 0)\n return 0;\n return (x === 0 && shape === 1) ? 1 / scale :\n Math.exp((shape - 1) * Math.log(x) - x / scale -\n jStat.gammaln(shape) - shape * Math.log(scale));\n },\n\n cdf: function cdf(x, shape, scale) {\n if (x < 0)\n return 0;\n return jStat.lowRegGamma(shape, x / scale);\n },\n\n inv: function(p, shape, scale) {\n return jStat.gammapinv(p, shape) * scale;\n },\n\n mean : function(shape, scale) {\n return shape * scale;\n },\n\n mode: function mode(shape, scale) {\n if(shape > 1) return (shape - 1) * scale;\n return undefined;\n },\n\n sample: function sample(shape, scale) {\n return jStat.randg(shape) * scale;\n },\n\n variance: function variance(shape, scale) {\n return shape * scale * scale;\n }\n});\n\n// extend inverse gamma function with static methods\njStat.extend(jStat.invgamma, {\n pdf: function pdf(x, shape, scale) {\n if (x <= 0)\n return 0;\n return Math.exp(-(shape + 1) * Math.log(x) - scale / x -\n jStat.gammaln(shape) + shape * Math.log(scale));\n },\n\n cdf: function cdf(x, shape, scale) {\n if (x <= 0)\n return 0;\n return 1 - jStat.lowRegGamma(shape, scale / x);\n },\n\n inv: function(p, shape, scale) {\n return scale / jStat.gammapinv(1 - p, shape);\n },\n\n mean : function(shape, scale) {\n return (shape > 1) ? scale / (shape - 1) : undefined;\n },\n\n mode: function mode(shape, scale) {\n return scale / (shape + 1);\n },\n\n sample: function sample(shape, scale) {\n return scale / jStat.randg(shape);\n },\n\n variance: function variance(shape, scale) {\n if (shape <= 2)\n return undefined;\n return scale * scale / ((shape - 1) * (shape - 1) * (shape - 2));\n }\n});\n\n\n// extend kumaraswamy function with static methods\njStat.extend(jStat.kumaraswamy, {\n pdf: function pdf(x, alpha, beta) {\n if (x === 0 && alpha === 1)\n return beta;\n else if (x === 1 && beta === 1)\n return alpha;\n return Math.exp(Math.log(alpha) + Math.log(beta) + (alpha - 1) *\n Math.log(x) + (beta - 1) *\n Math.log(1 - Math.pow(x, alpha)));\n },\n\n cdf: function cdf(x, alpha, beta) {\n if (x < 0)\n return 0;\n else if (x > 1)\n return 1;\n return (1 - Math.pow(1 - Math.pow(x, alpha), beta));\n },\n\n inv: function inv(p, alpha, beta) {\n return Math.pow(1 - Math.pow(1 - p, 1 / beta), 1 / alpha);\n },\n\n mean : function(alpha, beta) {\n return (beta * jStat.gammafn(1 + 1 / alpha) *\n jStat.gammafn(beta)) / (jStat.gammafn(1 + 1 / alpha + beta));\n },\n\n median: function median(alpha, beta) {\n return Math.pow(1 - Math.pow(2, -1 / beta), 1 / alpha);\n },\n\n mode: function mode(alpha, beta) {\n if (!(alpha >= 1 && beta >= 1 && (alpha !== 1 && beta !== 1)))\n return undefined;\n return Math.pow((alpha - 1) / (alpha * beta - 1), 1 / alpha);\n },\n\n variance: function variance(/*alpha, beta*/) {\n throw new Error('variance not yet implemented');\n // TODO: complete this\n }\n});\n\n\n\n// extend lognormal function with static methods\njStat.extend(jStat.lognormal, {\n pdf: function pdf(x, mu, sigma) {\n if (x <= 0)\n return 0;\n return Math.exp(-Math.log(x) - 0.5 * Math.log(2 * Math.PI) -\n Math.log(sigma) - Math.pow(Math.log(x) - mu, 2) /\n (2 * sigma * sigma));\n },\n\n cdf: function cdf(x, mu, sigma) {\n if (x < 0)\n return 0;\n return 0.5 +\n (0.5 * jStat.erf((Math.log(x) - mu) / Math.sqrt(2 * sigma * sigma)));\n },\n\n inv: function(p, mu, sigma) {\n return Math.exp(-1.41421356237309505 * sigma * jStat.erfcinv(2 * p) + mu);\n },\n\n mean: function mean(mu, sigma) {\n return Math.exp(mu + sigma * sigma / 2);\n },\n\n median: function median(mu/*, sigma*/) {\n return Math.exp(mu);\n },\n\n mode: function mode(mu, sigma) {\n return Math.exp(mu - sigma * sigma);\n },\n\n sample: function sample(mu, sigma) {\n return Math.exp(jStat.randn() * sigma + mu);\n },\n\n variance: function variance(mu, sigma) {\n return (Math.exp(sigma * sigma) - 1) * Math.exp(2 * mu + sigma * sigma);\n }\n});\n\n\n\n// extend noncentralt function with static methods\njStat.extend(jStat.noncentralt, {\n pdf: function pdf(x, dof, ncp) {\n var tol = 1e-14;\n if (Math.abs(ncp) < tol) // ncp approx 0; use student-t\n return jStat.studentt.pdf(x, dof)\n\n if (Math.abs(x) < tol) { // different formula for x == 0\n return Math.exp(jStat.gammaln((dof + 1) / 2) - ncp * ncp / 2 -\n 0.5 * Math.log(Math.PI * dof) - jStat.gammaln(dof / 2));\n }\n\n // formula for x != 0\n return dof / x *\n (jStat.noncentralt.cdf(x * Math.sqrt(1 + 2 / dof), dof+2, ncp) -\n jStat.noncentralt.cdf(x, dof, ncp));\n },\n\n cdf: function cdf(x, dof, ncp) {\n var tol = 1e-14;\n var min_iterations = 200;\n\n if (Math.abs(ncp) < tol) // ncp approx 0; use student-t\n return jStat.studentt.cdf(x, dof);\n\n // turn negative x into positive and flip result afterwards\n var flip = false;\n if (x < 0) {\n flip = true;\n ncp = -ncp;\n }\n\n var prob = jStat.normal.cdf(-ncp, 0, 1);\n var value = tol + 1;\n // use value at last two steps to determine convergence\n var lastvalue = value;\n var y = x * x / (x * x + dof);\n var j = 0;\n var p = Math.exp(-ncp * ncp / 2);\n var q = Math.exp(-ncp * ncp / 2 - 0.5 * Math.log(2) -\n jStat.gammaln(3 / 2)) * ncp;\n while (j < min_iterations || lastvalue > tol || value > tol) {\n lastvalue = value;\n if (j > 0) {\n p *= (ncp * ncp) / (2 * j);\n q *= (ncp * ncp) / (2 * (j + 1 / 2));\n }\n value = p * jStat.beta.cdf(y, j + 0.5, dof / 2) +\n q * jStat.beta.cdf(y, j+1, dof/2);\n prob += 0.5 * value;\n j++;\n }\n\n return flip ? (1 - prob) : prob;\n }\n});\n\n\n// extend normal function with static methods\njStat.extend(jStat.normal, {\n pdf: function pdf(x, mean, std) {\n return Math.exp(-0.5 * Math.log(2 * Math.PI) -\n Math.log(std) - Math.pow(x - mean, 2) / (2 * std * std));\n },\n\n cdf: function cdf(x, mean, std) {\n return 0.5 * (1 + jStat.erf((x - mean) / Math.sqrt(2 * std * std)));\n },\n\n inv: function(p, mean, std) {\n return -1.41421356237309505 * std * jStat.erfcinv(2 * p) + mean;\n },\n\n mean : function(mean/*, std*/) {\n return mean;\n },\n\n median: function median(mean/*, std*/) {\n return mean;\n },\n\n mode: function (mean/*, std*/) {\n return mean;\n },\n\n sample: function sample(mean, std) {\n return jStat.randn() * std + mean;\n },\n\n variance : function(mean, std) {\n return std * std;\n }\n});\n\n\n\n// extend pareto function with static methods\njStat.extend(jStat.pareto, {\n pdf: function pdf(x, scale, shape) {\n if (x < scale)\n return 0;\n return (shape * Math.pow(scale, shape)) / Math.pow(x, shape + 1);\n },\n\n cdf: function cdf(x, scale, shape) {\n if (x < scale)\n return 0;\n return 1 - Math.pow(scale / x, shape);\n },\n\n inv: function inv(p, scale, shape) {\n return scale / Math.pow(1 - p, 1 / shape);\n },\n\n mean: function mean(scale, shape) {\n if (shape <= 1)\n return undefined;\n return (shape * Math.pow(scale, shape)) / (shape - 1);\n },\n\n median: function median(scale, shape) {\n return scale * (shape * Math.SQRT2);\n },\n\n mode: function mode(scale/*, shape*/) {\n return scale;\n },\n\n variance : function(scale, shape) {\n if (shape <= 2)\n return undefined;\n return (scale*scale * shape) / (Math.pow(shape - 1, 2) * (shape - 2));\n }\n});\n\n\n\n// extend studentt function with static methods\njStat.extend(jStat.studentt, {\n pdf: function pdf(x, dof) {\n dof = dof > 1e100 ? 1e100 : dof;\n return (1/(Math.sqrt(dof) * jStat.betafn(0.5, dof/2))) *\n Math.pow(1 + ((x * x) / dof), -((dof + 1) / 2));\n },\n\n cdf: function cdf(x, dof) {\n var dof2 = dof / 2;\n return jStat.ibeta((x + Math.sqrt(x * x + dof)) /\n (2 * Math.sqrt(x * x + dof)), dof2, dof2);\n },\n\n inv: function(p, dof) {\n var x = jStat.ibetainv(2 * Math.min(p, 1 - p), 0.5 * dof, 0.5);\n x = Math.sqrt(dof * (1 - x) / x);\n return (p > 0.5) ? x : -x;\n },\n\n mean: function mean(dof) {\n return (dof > 1) ? 0 : undefined;\n },\n\n median: function median(/*dof*/) {\n return 0;\n },\n\n mode: function mode(/*dof*/) {\n return 0;\n },\n\n sample: function sample(dof) {\n return jStat.randn() * Math.sqrt(dof / (2 * jStat.randg(dof / 2)));\n },\n\n variance: function variance(dof) {\n return (dof > 2) ? dof / (dof - 2) : (dof > 1) ? Infinity : undefined;\n }\n});\n\n\n\n// extend weibull function with static methods\njStat.extend(jStat.weibull, {\n pdf: function pdf(x, scale, shape) {\n if (x < 0 || scale < 0 || shape < 0)\n return 0;\n return (shape / scale) * Math.pow((x / scale), (shape - 1)) *\n Math.exp(-(Math.pow((x / scale), shape)));\n },\n\n cdf: function cdf(x, scale, shape) {\n return x < 0 ? 0 : 1 - Math.exp(-Math.pow((x / scale), shape));\n },\n\n inv: function(p, scale, shape) {\n return scale * Math.pow(-Math.log(1 - p), 1 / shape);\n },\n\n mean : function(scale, shape) {\n return scale * jStat.gammafn(1 + 1 / shape);\n },\n\n median: function median(scale, shape) {\n return scale * Math.pow(Math.log(2), 1 / shape);\n },\n\n mode: function mode(scale, shape) {\n if (shape <= 1)\n return 0;\n return scale * Math.pow((shape - 1) / shape, 1 / shape);\n },\n\n sample: function sample(scale, shape) {\n return scale * Math.pow(-Math.log(jStat._random_fn()), 1 / shape);\n },\n\n variance: function variance(scale, shape) {\n return scale * scale * jStat.gammafn(1 + 2 / shape) -\n Math.pow(jStat.weibull.mean(scale, shape), 2);\n }\n});\n\n\n\n// extend uniform function with static methods\njStat.extend(jStat.uniform, {\n pdf: function pdf(x, a, b) {\n return (x < a || x > b) ? 0 : 1 / (b - a);\n },\n\n cdf: function cdf(x, a, b) {\n if (x < a)\n return 0;\n else if (x < b)\n return (x - a) / (b - a);\n return 1;\n },\n\n inv: function(p, a, b) {\n return a + (p * (b - a));\n },\n\n mean: function mean(a, b) {\n return 0.5 * (a + b);\n },\n\n median: function median(a, b) {\n return jStat.mean(a, b);\n },\n\n mode: function mode(/*a, b*/) {\n throw new Error('mode is not yet implemented');\n },\n\n sample: function sample(a, b) {\n return (a / 2 + b / 2) + (b / 2 - a / 2) * (2 * jStat._random_fn() - 1);\n },\n\n variance: function variance(a, b) {\n return Math.pow(b - a, 2) / 12;\n }\n});\n\n\n// Got this from http://www.math.ucla.edu/~tom/distributions/binomial.html\nfunction betinc(x, a, b, eps) {\n var a0 = 0;\n var b0 = 1;\n var a1 = 1;\n var b1 = 1;\n var m9 = 0;\n var a2 = 0;\n var c9;\n\n while (Math.abs((a1 - a2) / a1) > eps) {\n a2 = a1;\n c9 = -(a + m9) * (a + b + m9) * x / (a + 2 * m9) / (a + 2 * m9 + 1);\n a0 = a1 + c9 * a0;\n b0 = b1 + c9 * b0;\n m9 = m9 + 1;\n c9 = m9 * (b - m9) * x / (a + 2 * m9 - 1) / (a + 2 * m9);\n a1 = a0 + c9 * a1;\n b1 = b0 + c9 * b1;\n a0 = a0 / b1;\n b0 = b0 / b1;\n a1 = a1 / b1;\n b1 = 1;\n }\n\n return a1 / a;\n}\n\n\n// extend uniform function with static methods\njStat.extend(jStat.binomial, {\n pdf: function pdf(k, n, p) {\n return (p === 0 || p === 1) ?\n ((n * p) === k ? 1 : 0) :\n jStat.combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);\n },\n\n cdf: function cdf(x, n, p) {\n var betacdf;\n var eps = 1e-10;\n\n if (x < 0)\n return 0;\n if (x >= n)\n return 1;\n if (p < 0 || p > 1 || n <= 0)\n return NaN;\n\n x = Math.floor(x);\n var z = p;\n var a = x + 1;\n var b = n - x;\n var s = a + b;\n var bt = Math.exp(jStat.gammaln(s) - jStat.gammaln(b) -\n jStat.gammaln(a) + a * Math.log(z) + b * Math.log(1 - z));\n\n if (z < (a + 1) / (s + 2))\n betacdf = bt * betinc(z, a, b, eps);\n else\n betacdf = 1 - bt * betinc(1 - z, b, a, eps);\n\n return Math.round((1 - betacdf) * (1 / eps)) / (1 / eps);\n }\n});\n\n\n\n// extend uniform function with static methods\njStat.extend(jStat.negbin, {\n pdf: function pdf(k, r, p) {\n if (k !== k >>> 0)\n return false;\n if (k < 0)\n return 0;\n return jStat.combination(k + r - 1, r - 1) *\n Math.pow(1 - p, k) * Math.pow(p, r);\n },\n\n cdf: function cdf(x, r, p) {\n var sum = 0,\n k = 0;\n if (x < 0) return 0;\n for (; k <= x; k++) {\n sum += jStat.negbin.pdf(k, r, p);\n }\n return sum;\n }\n});\n\n\n\n// extend uniform function with static methods\njStat.extend(jStat.hypgeom, {\n pdf: function pdf(k, N, m, n) {\n // Hypergeometric PDF.\n\n // A simplification of the CDF algorithm below.\n\n // k = number of successes drawn\n // N = population size\n // m = number of successes in population\n // n = number of items drawn from population\n\n if(k !== k | 0) {\n return false;\n } else if(k < 0 || k < m - (N - n)) {\n // It's impossible to have this few successes drawn.\n return 0;\n } else if(k > n || k > m) {\n // It's impossible to have this many successes drawn.\n return 0;\n } else if (m * 2 > N) {\n // More than half the population is successes.\n\n if(n * 2 > N) {\n // More than half the population is sampled.\n\n return jStat.hypgeom.pdf(N - m - n + k, N, N - m, N - n)\n } else {\n // Half or less of the population is sampled.\n\n return jStat.hypgeom.pdf(n - k, N, N - m, n);\n }\n\n } else if(n * 2 > N) {\n // Half or less is successes.\n\n return jStat.hypgeom.pdf(m - k, N, m, N - n);\n\n } else if(m < n) {\n // We want to have the number of things sampled to be less than the\n // successes available. So swap the definitions of successful and sampled.\n return jStat.hypgeom.pdf(k, N, n, m);\n } else {\n // If we get here, half or less of the population was sampled, half or\n // less of it was successes, and we had fewer sampled things than\n // successes. Now we can do this complicated iterative algorithm in an\n // efficient way.\n\n // The basic premise of the algorithm is that we partially normalize our\n // intermediate product to keep it in a numerically good region, and then\n // finish the normalization at the end.\n\n // This variable holds the scaled probability of the current number of\n // successes.\n var scaledPDF = 1;\n\n // This keeps track of how much we have normalized.\n var samplesDone = 0;\n\n for(var i = 0; i < k; i++) {\n // For every possible number of successes up to that observed...\n\n while(scaledPDF > 1 && samplesDone < n) {\n // Intermediate result is growing too big. Apply some of the\n // normalization to shrink everything.\n\n scaledPDF *= 1 - (m / (N - samplesDone));\n\n // Say we've normalized by this sample already.\n samplesDone++;\n }\n\n // Work out the partially-normalized hypergeometric PDF for the next\n // number of successes\n scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1));\n }\n\n for(; samplesDone < n; samplesDone++) {\n // Apply all the rest of the normalization\n scaledPDF *= 1 - (m / (N - samplesDone));\n }\n\n // Bound answer sanely before returning.\n return Math.min(1, Math.max(0, scaledPDF));\n }\n },\n\n cdf: function cdf(x, N, m, n) {\n // Hypergeometric CDF.\n\n // This algorithm is due to Prof. Thomas S. Ferguson, <tom@math.ucla.edu>,\n // and comes from his hypergeometric test calculator at\n // <http://www.math.ucla.edu/~tom/distributions/Hypergeometric.html>.\n\n // x = number of successes drawn\n // N = population size\n // m = number of successes in population\n // n = number of items drawn from population\n\n if(x < 0 || x < m - (N - n)) {\n // It's impossible to have this few successes drawn or fewer.\n return 0;\n } else if(x >= n || x >= m) {\n // We will always have this many successes or fewer.\n return 1;\n } else if (m * 2 > N) {\n // More than half the population is successes.\n\n if(n * 2 > N) {\n // More than half the population is sampled.\n\n return jStat.hypgeom.cdf(N - m - n + x, N, N - m, N - n)\n } else {\n // Half or less of the population is sampled.\n\n return 1 - jStat.hypgeom.cdf(n - x - 1, N, N - m, n);\n }\n\n } else if(n * 2 > N) {\n // Half or less is successes.\n\n return 1 - jStat.hypgeom.cdf(m - x - 1, N, m, N - n);\n\n } else if(m < n) {\n // We want to have the number of things sampled to be less than the\n // successes available. So swap the definitions of successful and sampled.\n return jStat.hypgeom.cdf(x, N, n, m);\n } else {\n // If we get here, half or less of the population was sampled, half or\n // less of it was successes, and we had fewer sampled things than\n // successes. Now we can do this complicated iterative algorithm in an\n // efficient way.\n\n // The basic premise of the algorithm is that we partially normalize our\n // intermediate sum to keep it in a numerically good region, and then\n // finish the normalization at the end.\n\n // Holds the intermediate, scaled total CDF.\n var scaledCDF = 1;\n\n // This variable holds the scaled probability of the current number of\n // successes.\n var scaledPDF = 1;\n\n // This keeps track of how much we have normalized.\n var samplesDone = 0;\n\n for(var i = 0; i < x; i++) {\n // For every possible number of successes up to that observed...\n\n while(scaledCDF > 1 && samplesDone < n) {\n // Intermediate result is growing too big. Apply some of the\n // normalization to shrink everything.\n\n var factor = 1 - (m / (N - samplesDone));\n\n scaledPDF *= factor;\n scaledCDF *= factor;\n\n // Say we've normalized by this sample already.\n samplesDone++;\n }\n\n // Work out the partially-normalized hypergeometric PDF for the next\n // number of successes\n scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1));\n\n // Add to the CDF answer.\n scaledCDF += scaledPDF;\n }\n\n for(; samplesDone < n; samplesDone++) {\n // Apply all the rest of the normalization\n scaledCDF *= 1 - (m / (N - samplesDone));\n }\n\n // Bound answer sanely before returning.\n return Math.min(1, Math.max(0, scaledCDF));\n }\n }\n});\n\n\n\n// extend uniform function with static methods\njStat.extend(jStat.poisson, {\n pdf: function pdf(k, l) {\n if (l < 0 || (k % 1) !== 0 || k < 0) {\n return 0;\n }\n\n return Math.pow(l, k) * Math.exp(-l) / jStat.factorial(k);\n },\n\n cdf: function cdf(x, l) {\n var sumarr = [],\n k = 0;\n if (x < 0) return 0;\n for (; k <= x; k++) {\n sumarr.push(jStat.poisson.pdf(k, l));\n }\n return jStat.sum(sumarr);\n },\n\n mean : function(l) {\n return l;\n },\n\n variance : function(l) {\n return l;\n },\n\n sampleSmall: function sampleSmall(l) {\n var p = 1, k = 0, L = Math.exp(-l);\n do {\n k++;\n p *= jStat._random_fn();\n } while (p > L);\n return k - 1;\n },\n\n sampleLarge: function sampleLarge(l) {\n var lam = l;\n var k;\n var U, V, slam, loglam, a, b, invalpha, vr, us;\n\n slam = Math.sqrt(lam);\n loglam = Math.log(lam);\n b = 0.931 + 2.53 * slam;\n a = -0.059 + 0.02483 * b;\n invalpha = 1.1239 + 1.1328 / (b - 3.4);\n vr = 0.9277 - 3.6224 / (b - 2);\n\n while (1) {\n U = Math.random() - 0.5;\n V = Math.random();\n us = 0.5 - Math.abs(U);\n k = Math.floor((2 * a / us + b) * U + lam + 0.43);\n if ((us >= 0.07) && (V <= vr)) {\n return k;\n }\n if ((k < 0) || ((us < 0.013) && (V > us))) {\n continue;\n }\n /* log(V) == log(0.0) ok here */\n /* if U==0.0 so that us==0.0, log is ok since always returns */\n if ((Math.log(V) + Math.log(invalpha) - Math.log(a / (us * us) + b)) <= (-lam + k * loglam - jStat.loggam(k + 1))) {\n return k;\n }\n }\n },\n\n sample: function sample(l) {\n if (l < 10)\n return this.sampleSmall(l);\n else\n return this.sampleLarge(l);\n }\n});\n\n// extend triangular function with static methods\njStat.extend(jStat.triangular, {\n pdf: function pdf(x, a, b, c) {\n if (b <= a || c < a || c > b) {\n return NaN;\n } else {\n if (x < a || x > b) {\n return 0;\n } else if (x < c) {\n return (2 * (x - a)) / ((b - a) * (c - a));\n } else if (x === c) {\n return (2 / (b - a));\n } else { // x > c\n return (2 * (b - x)) / ((b - a) * (b - c));\n }\n }\n },\n\n cdf: function cdf(x, a, b, c) {\n if (b <= a || c < a || c > b)\n return NaN;\n if (x <= a)\n return 0;\n else if (x >= b)\n return 1;\n if (x <= c)\n return Math.pow(x - a, 2) / ((b - a) * (c - a));\n else // x > c\n return 1 - Math.pow(b - x, 2) / ((b - a) * (b - c));\n },\n\n inv: function inv(p, a, b, c) {\n if (b <= a || c < a || c > b) {\n return NaN;\n } else {\n if (p <= ((c - a) / (b - a))) {\n return a + (b - a) * Math.sqrt(p * ((c - a) / (b - a)));\n } else { // p > ((c - a) / (b - a))\n return a + (b - a) * (1 - Math.sqrt((1 - p) * (1 - ((c - a) / (b - a)))));\n }\n }\n },\n\n mean: function mean(a, b, c) {\n return (a + b + c) / 3;\n },\n\n median: function median(a, b, c) {\n if (c <= (a + b) / 2) {\n return b - Math.sqrt((b - a) * (b - c)) / Math.sqrt(2);\n } else if (c > (a + b) / 2) {\n return a + Math.sqrt((b - a) * (c - a)) / Math.sqrt(2);\n }\n },\n\n mode: function mode(a, b, c) {\n return c;\n },\n\n sample: function sample(a, b, c) {\n var u = jStat._random_fn();\n if (u < ((c - a) / (b - a)))\n return a + Math.sqrt(u * (b - a) * (c - a))\n return b - Math.sqrt((1 - u) * (b - a) * (b - c));\n },\n\n variance: function variance(a, b, c) {\n return (a * a + b * b + c * c - a * b - a * c - b * c) / 18;\n }\n});\n\n\n// extend arcsine function with static methods\njStat.extend(jStat.arcsine, {\n pdf: function pdf(x, a, b) {\n if (b <= a) return NaN;\n\n return (x <= a || x >= b) ? 0 :\n (2 / Math.PI) *\n Math.pow(Math.pow(b - a, 2) -\n Math.pow(2 * x - a - b, 2), -0.5);\n },\n\n cdf: function cdf(x, a, b) {\n if (x < a)\n return 0;\n else if (x < b)\n return (2 / Math.PI) * Math.asin(Math.sqrt((x - a)/(b - a)));\n return 1;\n },\n\n inv: function(p, a, b) {\n return a + (0.5 - 0.5 * Math.cos(Math.PI * p)) * (b - a);\n },\n\n mean: function mean(a, b) {\n if (b <= a) return NaN;\n return (a + b) / 2;\n },\n\n median: function median(a, b) {\n if (b <= a) return NaN;\n return (a + b) / 2;\n },\n\n mode: function mode(/*a, b*/) {\n throw new Error('mode is not yet implemented');\n },\n\n sample: function sample(a, b) {\n return ((a + b) / 2) + ((b - a) / 2) *\n Math.sin(2 * Math.PI * jStat.uniform.sample(0, 1));\n },\n\n variance: function variance(a, b) {\n if (b <= a) return NaN;\n return Math.pow(b - a, 2) / 8;\n }\n});\n\n\nfunction laplaceSign(x) { return x / Math.abs(x); }\n\njStat.extend(jStat.laplace, {\n pdf: function pdf(x, mu, b) {\n return (b <= 0) ? 0 : (Math.exp(-Math.abs(x - mu) / b)) / (2 * b);\n },\n\n cdf: function cdf(x, mu, b) {\n if (b <= 0) { return 0; }\n\n if(x < mu) {\n return 0.5 * Math.exp((x - mu) / b);\n } else {\n return 1 - 0.5 * Math.exp(- (x - mu) / b);\n }\n },\n\n mean: function(mu/*, b*/) {\n return mu;\n },\n\n median: function(mu/*, b*/) {\n return mu;\n },\n\n mode: function(mu/*, b*/) {\n return mu;\n },\n\n variance: function(mu, b) {\n return 2 * b * b;\n },\n\n sample: function sample(mu, b) {\n var u = jStat._random_fn() - 0.5;\n\n return mu - (b * laplaceSign(u) * Math.log(1 - (2 * Math.abs(u))));\n }\n});\n\nfunction tukeyWprob(w, rr, cc) {\n var nleg = 12;\n var ihalf = 6;\n\n var C1 = -30;\n var C2 = -50;\n var C3 = 60;\n var bb = 8;\n var wlar = 3;\n var wincr1 = 2;\n var wincr2 = 3;\n var xleg = [\n 0.981560634246719250690549090149,\n 0.904117256370474856678465866119,\n 0.769902674194304687036893833213,\n 0.587317954286617447296702418941,\n 0.367831498998180193752691536644,\n 0.125233408511468915472441369464\n ];\n var aleg = [\n 0.047175336386511827194615961485,\n 0.106939325995318430960254718194,\n 0.160078328543346226334652529543,\n 0.203167426723065921749064455810,\n 0.233492536538354808760849898925,\n 0.249147045813402785000562436043\n ];\n\n var qsqz = w * 0.5;\n\n // if w >= 16 then the integral lower bound (occurs for c=20)\n // is 0.99999999999995 so return a value of 1.\n\n if (qsqz >= bb)\n return 1.0;\n\n // find (f(w/2) - 1) ^ cc\n // (first term in integral of hartley's form).\n\n var pr_w = 2 * jStat.normal.cdf(qsqz, 0, 1, 1, 0) - 1; // erf(qsqz / M_SQRT2)\n // if pr_w ^ cc < 2e-22 then set pr_w = 0\n if (pr_w >= Math.exp(C2 / cc))\n pr_w = Math.pow(pr_w, cc);\n else\n pr_w = 0.0;\n\n // if w is large then the second component of the\n // integral is small, so fewer intervals are needed.\n\n var wincr;\n if (w > wlar)\n wincr = wincr1;\n else\n wincr = wincr2;\n\n // find the integral of second term of hartley's form\n // for the integral of the range for equal-length\n // intervals using legendre quadrature. limits of\n // integration are from (w/2, 8). two or three\n // equal-length intervals are used.\n\n // blb and bub are lower and upper limits of integration.\n\n var blb = qsqz;\n var binc = (bb - qsqz) / wincr;\n var bub = blb + binc;\n var einsum = 0.0;\n\n // integrate over each interval\n\n var cc1 = cc - 1.0;\n for (var wi = 1; wi <= wincr; wi++) {\n var elsum = 0.0;\n var a = 0.5 * (bub + blb);\n\n // legendre quadrature with order = nleg\n\n var b = 0.5 * (bub - blb);\n\n for (var jj = 1; jj <= nleg; jj++) {\n var j, xx;\n if (ihalf < jj) {\n j = (nleg - jj) + 1;\n xx = xleg[j-1];\n } else {\n j = jj;\n xx = -xleg[j-1];\n }\n var c = b * xx;\n var ac = a + c;\n\n // if exp(-qexpo/2) < 9e-14,\n // then doesn't contribute to integral\n\n var qexpo = ac * ac;\n if (qexpo > C3)\n break;\n\n var pplus = 2 * jStat.normal.cdf(ac, 0, 1, 1, 0);\n var pminus= 2 * jStat.normal.cdf(ac, w, 1, 1, 0);\n\n // if rinsum ^ (cc-1) < 9e-14,\n // then doesn't contribute to integral\n\n var rinsum = (pplus * 0.5) - (pminus * 0.5);\n if (rinsum >= Math.exp(C1 / cc1)) {\n rinsum = (aleg[j-1] * Math.exp(-(0.5 * qexpo))) * Math.pow(rinsum, cc1);\n elsum += rinsum;\n }\n }\n elsum *= (((2.0 * b) * cc) / Math.sqrt(2 * Math.PI));\n einsum += elsum;\n blb = bub;\n bub += binc;\n }\n\n // if pr_w ^ rr < 9e-14, then return 0\n pr_w += einsum;\n if (pr_w <= Math.exp(C1 / rr))\n return 0;\n\n pr_w = Math.pow(pr_w, rr);\n if (pr_w >= 1) // 1 was iMax was eps\n return 1;\n return pr_w;\n}\n\nfunction tukeyQinv(p, c, v) {\n var p0 = 0.322232421088;\n var q0 = 0.993484626060e-01;\n var p1 = -1.0;\n var q1 = 0.588581570495;\n var p2 = -0.342242088547;\n var q2 = 0.531103462366;\n var p3 = -0.204231210125;\n var q3 = 0.103537752850;\n var p4 = -0.453642210148e-04;\n var q4 = 0.38560700634e-02;\n var c1 = 0.8832;\n var c2 = 0.2368;\n var c3 = 1.214;\n var c4 = 1.208;\n var c5 = 1.4142;\n var vmax = 120.0;\n\n var ps = 0.5 - 0.5 * p;\n var yi = Math.sqrt(Math.log(1.0 / (ps * ps)));\n var t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0)\n / (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0);\n if (v < vmax) t += (t * t * t + t) / v / 4.0;\n var q = c1 - c2 * t;\n if (v < vmax) q += -c3 / v + c4 * t / v;\n return t * (q * Math.log(c - 1.0) + c5);\n}\n\njStat.extend(jStat.tukey, {\n cdf: function cdf(q, nmeans, df) {\n // Identical implementation as the R ptukey() function as of commit 68947\n var rr = 1;\n var cc = nmeans;\n\n var nlegq = 16;\n var ihalfq = 8;\n\n var eps1 = -30.0;\n var eps2 = 1.0e-14;\n var dhaf = 100.0;\n var dquar = 800.0;\n var deigh = 5000.0;\n var dlarg = 25000.0;\n var ulen1 = 1.0;\n var ulen2 = 0.5;\n var ulen3 = 0.25;\n var ulen4 = 0.125;\n var xlegq = [\n 0.989400934991649932596154173450,\n 0.944575023073232576077988415535,\n 0.865631202387831743880467897712,\n 0.755404408355003033895101194847,\n 0.617876244402643748446671764049,\n 0.458016777657227386342419442984,\n 0.281603550779258913230460501460,\n 0.950125098376374401853193354250e-1\n ];\n var alegq = [\n 0.271524594117540948517805724560e-1,\n 0.622535239386478928628438369944e-1,\n 0.951585116824927848099251076022e-1,\n 0.124628971255533872052476282192,\n 0.149595988816576732081501730547,\n 0.169156519395002538189312079030,\n 0.182603415044923588866763667969,\n 0.189450610455068496285396723208\n ];\n\n if (q <= 0)\n return 0;\n\n // df must be > 1\n // there must be at least two values\n\n if (df < 2 || rr < 1 || cc < 2) return NaN;\n\n if (!Number.isFinite(q))\n return 1;\n\n if (df > dlarg)\n return tukeyWprob(q, rr, cc);\n\n // calculate leading constant\n\n var f2 = df * 0.5;\n var f2lf = ((f2 * Math.log(df)) - (df * Math.log(2))) - jStat.gammaln(f2);\n var f21 = f2 - 1.0;\n\n // integral is divided into unit, half-unit, quarter-unit, or\n // eighth-unit length intervals depending on the value of the\n // degrees of freedom.\n\n var ff4 = df * 0.25;\n var ulen;\n if (df <= dhaf) ulen = ulen1;\n else if (df <= dquar) ulen = ulen2;\n else if (df <= deigh) ulen = ulen3;\n else ulen = ulen4;\n\n f2lf += Math.log(ulen);\n\n // integrate over each subinterval\n\n var ans = 0.0;\n\n for (var i = 1; i <= 50; i++) {\n var otsum = 0.0;\n\n // legendre quadrature with order = nlegq\n // nodes (stored in xlegq) are symmetric around zero.\n\n var twa1 = (2 * i - 1) * ulen;\n\n for (var jj = 1; jj <= nlegq; jj++) {\n var j, t1;\n if (ihalfq < jj) {\n j = jj - ihalfq - 1;\n t1 = (f2lf + (f21 * Math.log(twa1 + (xlegq[j] * ulen))))\n - (((xlegq[j] * ulen) + twa1) * ff4);\n } else {\n j = jj - 1;\n t1 = (f2lf + (f21 * Math.log(twa1 - (xlegq[j] * ulen))))\n + (((xlegq[j] * ulen) - twa1) * ff4);\n }\n\n // if exp(t1) < 9e-14, then doesn't contribute to integral\n var qsqz;\n if (t1 >= eps1) {\n if (ihalfq < jj) {\n qsqz = q * Math.sqrt(((xlegq[j] * ulen) + twa1) * 0.5);\n } else {\n qsqz = q * Math.sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5);\n }\n\n // call wprob to find integral of range portion\n\n var wprb = tukeyWprob(qsqz, rr, cc);\n var rotsum = (wprb * alegq[j]) * Math.exp(t1);\n otsum += rotsum;\n }\n // end legendre integral for interval i\n // L200:\n }\n\n // if integral for interval i < 1e-14, then stop.\n // However, in order to avoid small area under left tail,\n // at least 1 / ulen intervals are calculated.\n if (i * ulen >= 1.0 && otsum <= eps2)\n break;\n\n // end of interval i\n // L330:\n\n ans += otsum;\n }\n\n if (otsum > eps2) { // not converged\n throw new Error('tukey.cdf failed to converge');\n }\n if (ans > 1)\n ans = 1;\n return ans;\n },\n\n inv: function(p, nmeans, df) {\n // Identical implementation as the R qtukey() function as of commit 68947\n var rr = 1;\n var cc = nmeans;\n\n var eps = 0.0001;\n var maxiter = 50;\n\n // df must be > 1 ; there must be at least two values\n if (df < 2 || rr < 1 || cc < 2) return NaN;\n\n if (p < 0 || p > 1) return NaN;\n if (p === 0) return 0;\n if (p === 1) return Infinity;\n\n // Initial value\n\n var x0 = tukeyQinv(p, cc, df);\n\n // Find prob(value < x0)\n\n var valx0 = jStat.tukey.cdf(x0, nmeans, df) - p;\n\n // Find the second iterate and prob(value < x1).\n // If the first iterate has probability value\n // exceeding p then second iterate is 1 less than\n // first iterate; otherwise it is 1 greater.\n\n var x1;\n if (valx0 > 0.0)\n x1 = Math.max(0.0, x0 - 1.0);\n else\n x1 = x0 + 1.0;\n var valx1 = jStat.tukey.cdf(x1, nmeans, df) - p;\n\n // Find new iterate\n\n var ans;\n for(var iter = 1; iter < maxiter; iter++) {\n ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));\n valx0 = valx1;\n\n // New iterate must be >= 0\n\n x0 = x1;\n if (ans < 0.0) {\n ans = 0.0;\n valx1 = -p;\n }\n // Find prob(value < new iterate)\n\n valx1 = jStat.tukey.cdf(ans, nmeans, df) - p;\n x1 = ans;\n\n // If the difference between two successive\n // iterates is less than eps, stop\n\n var xabs = Math.abs(x1 - x0);\n if (xabs < eps)\n return ans;\n }\n\n throw new Error('tukey.inv failed to converge');\n }\n});\n\n}(jStat, Math));\n/* Provides functions for the solution of linear system of equations, integration, extrapolation,\n * interpolation, eigenvalue problems, differential equations and PCA analysis. */\n\n(function(jStat, Math) {\n\nvar push = Array.prototype.push;\nvar isArray = jStat.utils.isArray;\n\nfunction isUsable(arg) {\n return isArray(arg) || arg instanceof jStat;\n}\n\njStat.extend({\n\n // add a vector/matrix to a vector/matrix or scalar\n add: function add(arr, arg) {\n // check if arg is a vector or scalar\n if (isUsable(arg)) {\n if (!isUsable(arg[0])) arg = [ arg ];\n return jStat.map(arr, function(value, row, col) {\n return value + arg[row][col];\n });\n }\n return jStat.map(arr, function(value) { return value + arg; });\n },\n\n // subtract a vector or scalar from the vector\n subtract: function subtract(arr, arg) {\n // check if arg is a vector or scalar\n if (isUsable(arg)) {\n if (!isUsable(arg[0])) arg = [ arg ];\n return jStat.map(arr, function(value, row, col) {\n return value - arg[row][col] || 0;\n });\n }\n return jStat.map(arr, function(value) { return value - arg; });\n },\n\n // matrix division\n divide: function divide(arr, arg) {\n if (isUsable(arg)) {\n if (!isUsable(arg[0])) arg = [ arg ];\n return jStat.multiply(arr, jStat.inv(arg));\n }\n return jStat.map(arr, function(value) { return value / arg; });\n },\n\n // matrix multiplication\n multiply: function multiply(arr, arg) {\n var row, col, nrescols, sum, nrow, ncol, res, rescols;\n // eg: arr = 2 arg = 3 -> 6 for res[0][0] statement closure\n if (arr.length === undefined && arg.length === undefined) {\n return arr * arg;\n }\n nrow = arr.length,\n ncol = arr[0].length,\n res = jStat.zeros(nrow, nrescols = (isUsable(arg)) ? arg[0].length : ncol),\n rescols = 0;\n if (isUsable(arg)) {\n for (; rescols < nrescols; rescols++) {\n for (row = 0; row < nrow; row++) {\n sum = 0;\n for (col = 0; col < ncol; col++)\n sum += arr[row][col] * arg[col][rescols];\n res[row][rescols] = sum;\n }\n }\n return (nrow === 1 && rescols === 1) ? res[0][0] : res;\n }\n return jStat.map(arr, function(value) { return value * arg; });\n },\n\n // outer([1,2,3],[4,5,6])\n // ===\n // [[1],[2],[3]] times [[4,5,6]]\n // ->\n // [[4,5,6],[8,10,12],[12,15,18]]\n outer:function outer(A, B) {\n return jStat.multiply(A.map(function(t){ return [t] }), [B]);\n },\n\n\n // Returns the dot product of two matricies\n dot: function dot(arr, arg) {\n if (!isUsable(arr[0])) arr = [ arr ];\n if (!isUsable(arg[0])) arg = [ arg ];\n // convert column to row vector\n var left = (arr[0].length === 1 && arr.length !== 1) ? jStat.transpose(arr) : arr,\n right = (arg[0].length === 1 && arg.length !== 1) ? jStat.transpose(arg) : arg,\n res = [],\n row = 0,\n nrow = left.length,\n ncol = left[0].length,\n sum, col;\n for (; row < nrow; row++) {\n res[row] = [];\n sum = 0;\n for (col = 0; col < ncol; col++)\n sum += left[row][col] * right[row][col];\n res[row] = sum;\n }\n return (res.length === 1) ? res[0] : res;\n },\n\n // raise every element by a scalar\n pow: function pow(arr, arg) {\n return jStat.map(arr, function(value) { return Math.pow(value, arg); });\n },\n\n // exponentiate every element\n exp: function exp(arr) {\n return jStat.map(arr, function(value) { return Math.exp(value); });\n },\n\n // generate the natural log of every element\n log: function exp(arr) {\n return jStat.map(arr, function(value) { return Math.log(value); });\n },\n\n // generate the absolute values of the vector\n abs: function abs(arr) {\n return jStat.map(arr, function(value) { return Math.abs(value); });\n },\n\n // computes the p-norm of the vector\n // In the case that a matrix is passed, uses the first row as the vector\n norm: function norm(arr, p) {\n var nnorm = 0,\n i = 0;\n // check the p-value of the norm, and set for most common case\n if (isNaN(p)) p = 2;\n // check if multi-dimensional array, and make vector correction\n if (isUsable(arr[0])) arr = arr[0];\n // vector norm\n for (; i < arr.length; i++) {\n nnorm += Math.pow(Math.abs(arr[i]), p);\n }\n return Math.pow(nnorm, 1 / p);\n },\n\n // computes the angle between two vectors in rads\n // In case a matrix is passed, this uses the first row as the vector\n angle: function angle(arr, arg) {\n return Math.acos(jStat.dot(arr, arg) / (jStat.norm(arr) * jStat.norm(arg)));\n },\n\n // augment one matrix by another\n // Note: this function returns a matrix, not a jStat object\n aug: function aug(a, b) {\n var newarr = [];\n var i;\n for (i = 0; i < a.length; i++) {\n newarr.push(a[i].slice());\n }\n for (i = 0; i < newarr.length; i++) {\n push.apply(newarr[i], b[i]);\n }\n return newarr;\n },\n\n // The inv() function calculates the inverse of a matrix\n // Create the inverse by augmenting the matrix by the identity matrix of the\n // appropriate size, and then use G-J elimination on the augmented matrix.\n inv: function inv(a) {\n var rows = a.length;\n var cols = a[0].length;\n var b = jStat.identity(rows, cols);\n var c = jStat.gauss_jordan(a, b);\n var result = [];\n var i = 0;\n var j;\n\n //We need to copy the inverse portion to a new matrix to rid G-J artifacts\n for (; i < rows; i++) {\n result[i] = [];\n for (j = cols; j < c[0].length; j++)\n result[i][j - cols] = c[i][j];\n }\n return result;\n },\n\n // calculate the determinant of a matrix\n det: function det(a) {\n if (a.length === 2) {\n return a[0][0] * a[1][1] - a[0][1] * a[1][0];\n }\n\n var determinant = 0;\n for (var i = 0; i < a.length; i++) {\n // build a sub matrix without column `i`\n var submatrix = [];\n for (var row = 1; row < a.length; row++) {\n submatrix[row - 1] = [];\n for (var col = 0; col < a.length; col++) {\n if (col < i) {\n submatrix[row - 1][col] = a[row][col];\n } else if (col > i) {\n submatrix[row - 1][col - 1] = a[row][col];\n }\n }\n }\n\n // alternate between + and - between determinants\n var sign = i % 2 ? -1 : 1;\n determinant += det(submatrix) * a[0][i] * sign;\n }\n\n return determinant\n },\n\n gauss_elimination: function gauss_elimination(a, b) {\n var i = 0,\n j = 0,\n n = a.length,\n m = a[0].length,\n factor = 1,\n sum = 0,\n x = [],\n maug, pivot, temp, k;\n a = jStat.aug(a, b);\n maug = a[0].length;\n for(i = 0; i < n; i++) {\n pivot = a[i][i];\n j = i;\n for (k = i + 1; k < m; k++) {\n if (pivot < Math.abs(a[k][i])) {\n pivot = a[k][i];\n j = k;\n }\n }\n if (j != i) {\n for(k = 0; k < maug; k++) {\n temp = a[i][k];\n a[i][k] = a[j][k];\n a[j][k] = temp;\n }\n }\n for (j = i + 1; j < n; j++) {\n factor = a[j][i] / a[i][i];\n for(k = i; k < maug; k++) {\n a[j][k] = a[j][k] - factor * a[i][k];\n }\n }\n }\n for (i = n - 1; i >= 0; i--) {\n sum = 0;\n for (j = i + 1; j<= n - 1; j++) {\n sum = sum + x[j] * a[i][j];\n }\n x[i] =(a[i][maug - 1] - sum) / a[i][i];\n }\n return x;\n },\n\n gauss_jordan: function gauss_jordan(a, b) {\n var m = jStat.aug(a, b);\n var h = m.length;\n var w = m[0].length;\n var c = 0;\n var x, y, y2;\n // find max pivot\n for (y = 0; y < h; y++) {\n var maxrow = y;\n for (y2 = y+1; y2 < h; y2++) {\n if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y]))\n maxrow = y2;\n }\n var tmp = m[y];\n m[y] = m[maxrow];\n m[maxrow] = tmp\n for (y2 = y+1; y2 < h; y2++) {\n c = m[y2][y] / m[y][y];\n for (x = y; x < w; x++) {\n m[y2][x] -= m[y][x] * c;\n }\n }\n }\n // backsubstitute\n for (y = h-1; y >= 0; y--) {\n c = m[y][y];\n for (y2 = 0; y2 < y; y2++) {\n for (x = w-1; x > y-1; x--) {\n m[y2][x] -= m[y][x] * m[y2][y] / c;\n }\n }\n m[y][y] /= c;\n for (x = h; x < w; x++) {\n m[y][x] /= c;\n }\n }\n return m;\n },\n\n // solve equation\n // Ax=b\n // A is upper triangular matrix\n // A=[[1,2,3],[0,4,5],[0,6,7]]\n // b=[1,2,3]\n // triaUpSolve(A,b) // -> [2.666,0.1666,1.666]\n // if you use matrix style\n // A=[[1,2,3],[0,4,5],[0,6,7]]\n // b=[[1],[2],[3]]\n // will return [[2.666],[0.1666],[1.666]]\n triaUpSolve: function triaUpSolve(A, b) {\n var size = A[0].length;\n var x = jStat.zeros(1, size)[0];\n var parts;\n var matrix_mode = false;\n\n if (b[0].length != undefined) {\n b = b.map(function(i){ return i[0] });\n matrix_mode = true;\n }\n\n jStat.arange(size - 1, -1, -1).forEach(function(i) {\n parts = jStat.arange(i + 1, size).map(function(j) {\n return x[j] * A[i][j];\n });\n x[i] = (b[i] - jStat.sum(parts)) / A[i][i];\n });\n\n if (matrix_mode)\n return x.map(function(i){ return [i] });\n return x;\n },\n\n triaLowSolve: function triaLowSolve(A, b) {\n // like to triaUpSolve but A is lower triangular matrix\n var size = A[0].length;\n var x = jStat.zeros(1, size)[0];\n var parts;\n\n var matrix_mode=false;\n if (b[0].length != undefined) {\n b = b.map(function(i){ return i[0] });\n matrix_mode = true;\n }\n\n jStat.arange(size).forEach(function(i) {\n parts = jStat.arange(i).map(function(j) {\n return A[i][j] * x[j];\n });\n x[i] = (b[i] - jStat.sum(parts)) / A[i][i];\n })\n\n if (matrix_mode)\n return x.map(function(i){ return [i] });\n return x;\n },\n\n\n // A -> [L,U]\n // A=LU\n // L is lower triangular matrix\n // U is upper triangular matrix\n lu: function lu(A) {\n var size = A.length;\n //var L=jStat.diagonal(jStat.ones(1,size)[0]);\n var L = jStat.identity(size);\n var R = jStat.zeros(A.length, A[0].length);\n var parts;\n jStat.arange(size).forEach(function(t) {\n R[0][t] = A[0][t];\n });\n jStat.arange(1, size).forEach(function(l) {\n jStat.arange(l).forEach(function(i) {\n parts = jStat.arange(i).map(function(jj) {\n return L[l][jj] * R[jj][i];\n });\n L[l][i] = (A[l][i] - jStat.sum(parts)) / R[i][i];\n });\n jStat.arange(l, size).forEach(function(j) {\n parts = jStat.arange(l).map(function(jj) {\n return L[l][jj] * R[jj][j];\n });\n R[l][j] = A[parts.length][j] - jStat.sum(parts);\n });\n });\n return [L, R];\n },\n\n // A -> T\n // A=TT'\n // T is lower triangular matrix\n cholesky: function cholesky(A) {\n var size = A.length;\n var T = jStat.zeros(A.length, A[0].length);\n var parts;\n jStat.arange(size).forEach(function(i) {\n parts = jStat.arange(i).map(function(t) {\n return Math.pow(T[i][t],2);\n });\n T[i][i] = Math.sqrt(A[i][i] - jStat.sum(parts));\n jStat.arange(i + 1, size).forEach(function(j) {\n parts = jStat.arange(i).map(function(t) {\n return T[i][t] * T[j][t];\n });\n T[j][i] = (A[i][j] - jStat.sum(parts)) / T[i][i];\n });\n });\n return T;\n },\n\n\n gauss_jacobi: function gauss_jacobi(a, b, x, r) {\n var i = 0;\n var j = 0;\n var n = a.length;\n var l = [];\n var u = [];\n var d = [];\n var xv, c, h, xk;\n for (; i < n; i++) {\n l[i] = [];\n u[i] = [];\n d[i] = [];\n for (j = 0; j < n; j++) {\n if (i > j) {\n l[i][j] = a[i][j];\n u[i][j] = d[i][j] = 0;\n } else if (i < j) {\n u[i][j] = a[i][j];\n l[i][j] = d[i][j] = 0;\n } else {\n d[i][j] = a[i][j];\n l[i][j] = u[i][j] = 0;\n }\n }\n }\n h = jStat.multiply(jStat.multiply(jStat.inv(d), jStat.add(l, u)), -1);\n c = jStat.multiply(jStat.inv(d), b);\n xv = x;\n xk = jStat.add(jStat.multiply(h, x), c);\n i = 2;\n while (Math.abs(jStat.norm(jStat.subtract(xk,xv))) > r) {\n xv = xk;\n xk = jStat.add(jStat.multiply(h, xv), c);\n i++;\n }\n return xk;\n },\n\n gauss_seidel: function gauss_seidel(a, b, x, r) {\n var i = 0;\n var n = a.length;\n var l = [];\n var u = [];\n var d = [];\n var j, xv, c, h, xk;\n for (; i < n; i++) {\n l[i] = [];\n u[i] = [];\n d[i] = [];\n for (j = 0; j < n; j++) {\n if (i > j) {\n l[i][j] = a[i][j];\n u[i][j] = d[i][j] = 0;\n } else if (i < j) {\n u[i][j] = a[i][j];\n l[i][j] = d[i][j] = 0;\n } else {\n d[i][j] = a[i][j];\n l[i][j] = u[i][j] = 0;\n }\n }\n }\n h = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d, l)), u), -1);\n c = jStat.multiply(jStat.inv(jStat.add(d, l)), b);\n xv = x;\n xk = jStat.add(jStat.multiply(h, x), c);\n i = 2;\n while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {\n xv = xk;\n xk = jStat.add(jStat.multiply(h, xv), c);\n i = i + 1;\n }\n return xk;\n },\n\n SOR: function SOR(a, b, x, r, w) {\n var i = 0;\n var n = a.length;\n var l = [];\n var u = [];\n var d = [];\n var j, xv, c, h, xk;\n for (; i < n; i++) {\n l[i] = [];\n u[i] = [];\n d[i] = [];\n for (j = 0; j < n; j++) {\n if (i > j) {\n l[i][j] = a[i][j];\n u[i][j] = d[i][j] = 0;\n } else if (i < j) {\n u[i][j] = a[i][j];\n l[i][j] = d[i][j] = 0;\n } else {\n d[i][j] = a[i][j];\n l[i][j] = u[i][j] = 0;\n }\n }\n }\n h = jStat.multiply(jStat.inv(jStat.add(d, jStat.multiply(l, w))),\n jStat.subtract(jStat.multiply(d, 1 - w),\n jStat.multiply(u, w)));\n c = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d,\n jStat.multiply(l, w))), b), w);\n xv = x;\n xk = jStat.add(jStat.multiply(h, x), c);\n i = 2;\n while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) {\n xv = xk;\n xk = jStat.add(jStat.multiply(h, xv), c);\n i++;\n }\n return xk;\n },\n\n householder: function householder(a) {\n var m = a.length;\n var n = a[0].length;\n var i = 0;\n var w = [];\n var p = [];\n var alpha, r, k, j, factor;\n for (; i < m - 1; i++) {\n alpha = 0;\n for (j = i + 1; j < n; j++)\n alpha += (a[j][i] * a[j][i]);\n factor = (a[i + 1][i] > 0) ? -1 : 1;\n alpha = factor * Math.sqrt(alpha);\n r = Math.sqrt((((alpha * alpha) - a[i + 1][i] * alpha) / 2));\n w = jStat.zeros(m, 1);\n w[i + 1][0] = (a[i + 1][i] - alpha) / (2 * r);\n for (k = i + 2; k < m; k++) w[k][0] = a[k][i] / (2 * r);\n p = jStat.subtract(jStat.identity(m, n),\n jStat.multiply(jStat.multiply(w, jStat.transpose(w)), 2));\n a = jStat.multiply(p, jStat.multiply(a, p));\n }\n return a;\n },\n\n // A -> [Q,R]\n // Q is orthogonal matrix\n // R is upper triangular\n QR: (function() {\n // x -> Q\n // find a orthogonal matrix Q st.\n // Qx=y\n // y is [||x||,0,0,...]\n\n // quick ref\n var sum = jStat.sum;\n var range = jStat.arange;\n\n function qr2(x) {\n // quick impletation\n // https://www.stat.wisc.edu/~larget/math496/qr.html\n\n var n = x.length;\n var p = x[0].length;\n\n var r = jStat.zeros(p, p);\n x = jStat.copy(x);\n\n var i,j,k;\n for(j = 0; j < p; j++){\n r[j][j] = Math.sqrt(sum(range(n).map(function(i){\n return x[i][j] * x[i][j];\n })));\n for(i = 0; i < n; i++){\n x[i][j] = x[i][j] / r[j][j];\n }\n for(k = j+1; k < p; k++){\n r[j][k] = sum(range(n).map(function(i){\n return x[i][j] * x[i][k];\n }));\n for(i = 0; i < n; i++){\n x[i][k] = x[i][k] - x[i][j]*r[j][k];\n }\n }\n }\n return [x, r];\n }\n\n return qr2;\n }()),\n\n lstsq: (function() {\n // solve least squard problem for Ax=b as QR decomposition way if b is\n // [[b1],[b2],[b3]] form will return [[x1],[x2],[x3]] array form solution\n // else b is [b1,b2,b3] form will return [x1,x2,x3] array form solution\n function R_I(A) {\n A = jStat.copy(A);\n var size = A.length;\n var I = jStat.identity(size);\n jStat.arange(size - 1, -1, -1).forEach(function(i) {\n jStat.sliceAssign(\n I, { row: i }, jStat.divide(jStat.slice(I, { row: i }), A[i][i]));\n jStat.sliceAssign(\n A, { row: i }, jStat.divide(jStat.slice(A, { row: i }), A[i][i]));\n jStat.arange(i).forEach(function(j) {\n var c = jStat.multiply(A[j][i], -1);\n var Aj = jStat.slice(A, { row: j });\n var cAi = jStat.multiply(jStat.slice(A, { row: i }), c);\n jStat.sliceAssign(A, { row: j }, jStat.add(Aj, cAi));\n var Ij = jStat.slice(I, { row: j });\n var cIi = jStat.multiply(jStat.slice(I, { row: i }), c);\n jStat.sliceAssign(I, { row: j }, jStat.add(Ij, cIi));\n })\n });\n return I;\n }\n\n function qr_solve(A, b){\n var array_mode = false;\n if (b[0].length === undefined) {\n // [c1,c2,c3] mode\n b = b.map(function(x){ return [x] });\n array_mode = true;\n }\n var QR = jStat.QR(A);\n var Q = QR[0];\n var R = QR[1];\n var attrs = A[0].length;\n var Q1 = jStat.slice(Q,{col:{end:attrs}});\n var R1 = jStat.slice(R,{row:{end:attrs}});\n var RI = R_I(R1);\n var Q2 = jStat.transpose(Q1);\n\n if(Q2[0].length === undefined){\n Q2 = [Q2]; // The confusing jStat.multifly implementation threat nature process again.\n }\n\n var x = jStat.multiply(jStat.multiply(RI, Q2), b);\n\n if(x.length === undefined){\n x = [[x]]; // The confusing jStat.multifly implementation threat nature process again.\n }\n\n\n if (array_mode)\n return x.map(function(i){ return i[0] });\n return x;\n }\n\n return qr_solve;\n }()),\n\n jacobi: function jacobi(a) {\n var condition = 1;\n var n = a.length;\n var e = jStat.identity(n, n);\n var ev = [];\n var b, i, j, p, q, maxim, theta, s;\n // condition === 1 only if tolerance is not reached\n while (condition === 1) {\n maxim = a[0][1];\n p = 0;\n q = 1;\n for (i = 0; i < n; i++) {\n for (j = 0; j < n; j++) {\n if (i != j) {\n if (maxim < Math.abs(a[i][j])) {\n maxim = Math.abs(a[i][j]);\n p = i;\n q = j;\n }\n }\n }\n }\n if (a[p][p] === a[q][q])\n theta = (a[p][q] > 0) ? Math.PI / 4 : -Math.PI / 4;\n else\n theta = Math.atan(2 * a[p][q] / (a[p][p] - a[q][q])) / 2;\n s = jStat.identity(n, n);\n s[p][p] = Math.cos(theta);\n s[p][q] = -Math.sin(theta);\n s[q][p] = Math.sin(theta);\n s[q][q] = Math.cos(theta);\n // eigen vector matrix\n e = jStat.multiply(e, s);\n b = jStat.multiply(jStat.multiply(jStat.inv(s), a), s);\n a = b;\n condition = 0;\n for (i = 1; i < n; i++) {\n for (j = 1; j < n; j++) {\n if (i != j && Math.abs(a[i][j]) > 0.001) {\n condition = 1;\n }\n }\n }\n }\n for (i = 0; i < n; i++) ev.push(a[i][i]);\n //returns both the eigenvalue and eigenmatrix\n return [e, ev];\n },\n\n rungekutta: function rungekutta(f, h, p, t_j, u_j, order) {\n var k1, k2, u_j1, k3, k4;\n if (order === 2) {\n while (t_j <= p) {\n k1 = h * f(t_j, u_j);\n k2 = h * f(t_j + h, u_j + k1);\n u_j1 = u_j + (k1 + k2) / 2;\n u_j = u_j1;\n t_j = t_j + h;\n }\n }\n if (order === 4) {\n while (t_j <= p) {\n k1 = h * f(t_j, u_j);\n k2 = h * f(t_j + h / 2, u_j + k1 / 2);\n k3 = h * f(t_j + h / 2, u_j + k2 / 2);\n k4 = h * f(t_j +h, u_j + k3);\n u_j1 = u_j + (k1 + 2 * k2 + 2 * k3 + k4) / 6;\n u_j = u_j1;\n t_j = t_j + h;\n }\n }\n return u_j;\n },\n\n romberg: function romberg(f, a, b, order) {\n var i = 0;\n var h = (b - a) / 2;\n var x = [];\n var h1 = [];\n var g = [];\n var m, a1, j, k, I;\n while (i < order / 2) {\n I = f(a);\n for (j = a, k = 0; j <= b; j = j + h, k++) x[k] = j;\n m = x.length;\n for (j = 1; j < m - 1; j++) {\n I += (((j % 2) !== 0) ? 4 : 2) * f(x[j]);\n }\n I = (h / 3) * (I + f(b));\n g[i] = I;\n h /= 2;\n i++;\n }\n a1 = g.length;\n m = 1;\n while (a1 !== 1) {\n for (j = 0; j < a1 - 1; j++)\n h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);\n a1 = h1.length;\n g = h1;\n h1 = [];\n m++;\n }\n return g;\n },\n\n richardson: function richardson(X, f, x, h) {\n function pos(X, x) {\n var i = 0;\n var n = X.length;\n var p;\n for (; i < n; i++)\n if (X[i] === x) p = i;\n return p;\n }\n var h_min = Math.abs(x - X[pos(X, x) + 1]);\n var i = 0;\n var g = [];\n var h1 = [];\n var y1, y2, m, a, j;\n while (h >= h_min) {\n y1 = pos(X, x + h);\n y2 = pos(X, x);\n g[i] = (f[y1] - 2 * f[y2] + f[2 * y2 - y1]) / (h * h);\n h /= 2;\n i++;\n }\n a = g.length;\n m = 1;\n while (a != 1) {\n for (j = 0; j < a - 1; j++)\n h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1);\n a = h1.length;\n g = h1;\n h1 = [];\n m++;\n }\n return g;\n },\n\n simpson: function simpson(f, a, b, n) {\n var h = (b - a) / n;\n var I = f(a);\n var x = [];\n var j = a;\n var k = 0;\n var i = 1;\n var m;\n for (; j <= b; j = j + h, k++)\n x[k] = j;\n m = x.length;\n for (; i < m - 1; i++) {\n I += ((i % 2 !== 0) ? 4 : 2) * f(x[i]);\n }\n return (h / 3) * (I + f(b));\n },\n\n hermite: function hermite(X, F, dF, value) {\n var n = X.length;\n var p = 0;\n var i = 0;\n var l = [];\n var dl = [];\n var A = [];\n var B = [];\n var j;\n for (; i < n; i++) {\n l[i] = 1;\n for (j = 0; j < n; j++) {\n if (i != j) l[i] *= (value - X[j]) / (X[i] - X[j]);\n }\n dl[i] = 0;\n for (j = 0; j < n; j++) {\n if (i != j) dl[i] += 1 / (X [i] - X[j]);\n }\n A[i] = (1 - 2 * (value - X[i]) * dl[i]) * (l[i] * l[i]);\n B[i] = (value - X[i]) * (l[i] * l[i]);\n p += (A[i] * F[i] + B[i] * dF[i]);\n }\n return p;\n },\n\n lagrange: function lagrange(X, F, value) {\n var p = 0;\n var i = 0;\n var j, l;\n var n = X.length;\n for (; i < n; i++) {\n l = F[i];\n for (j = 0; j < n; j++) {\n // calculating the lagrange polynomial L_i\n if (i != j) l *= (value - X[j]) / (X[i] - X[j]);\n }\n // adding the lagrange polynomials found above\n p += l;\n }\n return p;\n },\n\n cubic_spline: function cubic_spline(X, F, value) {\n var n = X.length;\n var i = 0, j;\n var A = [];\n var B = [];\n var alpha = [];\n var c = [];\n var h = [];\n var b = [];\n var d = [];\n for (; i < n - 1; i++)\n h[i] = X[i + 1] - X[i];\n alpha[0] = 0;\n for (i = 1; i < n - 1; i++) {\n alpha[i] = (3 / h[i]) * (F[i + 1] - F[i]) -\n (3 / h[i-1]) * (F[i] - F[i-1]);\n }\n for (i = 1; i < n - 1; i++) {\n A[i] = [];\n B[i] = [];\n A[i][i-1] = h[i-1];\n A[i][i] = 2 * (h[i - 1] + h[i]);\n A[i][i+1] = h[i];\n B[i][0] = alpha[i];\n }\n c = jStat.multiply(jStat.inv(A), B);\n for (j = 0; j < n - 1; j++) {\n b[j] = (F[j + 1] - F[j]) / h[j] - h[j] * (c[j + 1][0] + 2 * c[j][0]) / 3;\n d[j] = (c[j + 1][0] - c[j][0]) / (3 * h[j]);\n }\n for (j = 0; j < n; j++) {\n if (X[j] > value) break;\n }\n j -= 1;\n return F[j] + (value - X[j]) * b[j] + jStat.sq(value-X[j]) *\n c[j] + (value - X[j]) * jStat.sq(value - X[j]) * d[j];\n },\n\n gauss_quadrature: function gauss_quadrature() {\n throw new Error('gauss_quadrature not yet implemented');\n },\n\n PCA: function PCA(X) {\n var m = X.length;\n var n = X[0].length;\n var i = 0;\n var j, temp1;\n var u = [];\n var D = [];\n var result = [];\n var temp2 = [];\n var Y = [];\n var Bt = [];\n var B = [];\n var C = [];\n var V = [];\n var Vt = [];\n for (i = 0; i < m; i++) {\n u[i] = jStat.sum(X[i]) / n;\n }\n for (i = 0; i < n; i++) {\n B[i] = [];\n for(j = 0; j < m; j++) {\n B[i][j] = X[j][i] - u[j];\n }\n }\n B = jStat.transpose(B);\n for (i = 0; i < m; i++) {\n C[i] = [];\n for (j = 0; j < m; j++) {\n C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1);\n }\n }\n result = jStat.jacobi(C);\n V = result[0];\n D = result[1];\n Vt = jStat.transpose(V);\n for (i = 0; i < D.length; i++) {\n for (j = i; j < D.length; j++) {\n if(D[i] < D[j]) {\n temp1 = D[i];\n D[i] = D[j];\n D[j] = temp1;\n temp2 = Vt[i];\n Vt[i] = Vt[j];\n Vt[j] = temp2;\n }\n }\n }\n Bt = jStat.transpose(B);\n for (i = 0; i < m; i++) {\n Y[i] = [];\n for (j = 0; j < Bt.length; j++) {\n Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]);\n }\n }\n return [X, D, Vt, Y];\n }\n});\n\n// extend jStat.fn with methods that require one argument\n(function(funcs) {\n for (var i = 0; i < funcs.length; i++) (function(passfunc) {\n jStat.fn[passfunc] = function(arg, func) {\n var tmpthis = this;\n // check for callback\n if (func) {\n setTimeout(function() {\n func.call(tmpthis, jStat.fn[passfunc].call(tmpthis, arg));\n }, 15);\n return this;\n }\n if (typeof jStat[passfunc](this, arg) === 'number')\n return jStat[passfunc](this, arg);\n else\n return jStat(jStat[passfunc](this, arg));\n };\n }(funcs[i]));\n}('add divide multiply subtract dot pow exp log abs norm angle'.split(' ')));\n\n}(jStat, Math));\n(function(jStat, Math) {\n\nvar slice = [].slice;\nvar isNumber = jStat.utils.isNumber;\nvar isArray = jStat.utils.isArray;\n\n// flag==true denotes use of sample standard deviation\n// Z Statistics\njStat.extend({\n // 2 different parameter lists:\n // (value, mean, sd)\n // (value, array, flag)\n zscore: function zscore() {\n var args = slice.call(arguments);\n if (isNumber(args[1])) {\n return (args[0] - args[1]) / args[2];\n }\n return (args[0] - jStat.mean(args[1])) / jStat.stdev(args[1], args[2]);\n },\n\n // 3 different paramter lists:\n // (value, mean, sd, sides)\n // (zscore, sides)\n // (value, array, sides, flag)\n ztest: function ztest() {\n var args = slice.call(arguments);\n var z;\n if (isArray(args[1])) {\n // (value, array, sides, flag)\n z = jStat.zscore(args[0],args[1],args[3]);\n return (args[2] === 1) ?\n (jStat.normal.cdf(-Math.abs(z), 0, 1)) :\n (jStat.normal.cdf(-Math.abs(z), 0, 1)*2);\n } else {\n if (args.length > 2) {\n // (value, mean, sd, sides)\n z = jStat.zscore(args[0],args[1],args[2]);\n return (args[3] === 1) ?\n (jStat.normal.cdf(-Math.abs(z),0,1)) :\n (jStat.normal.cdf(-Math.abs(z),0,1)* 2);\n } else {\n // (zscore, sides)\n z = args[0];\n return (args[1] === 1) ?\n (jStat.normal.cdf(-Math.abs(z),0,1)) :\n (jStat.normal.cdf(-Math.abs(z),0,1)*2);\n }\n }\n }\n});\n\njStat.extend(jStat.fn, {\n zscore: function zscore(value, flag) {\n return (value - this.mean()) / this.stdev(flag);\n },\n\n ztest: function ztest(value, sides, flag) {\n var zscore = Math.abs(this.zscore(value, flag));\n return (sides === 1) ?\n (jStat.normal.cdf(-zscore, 0, 1)) :\n (jStat.normal.cdf(-zscore, 0, 1) * 2);\n }\n});\n\n// T Statistics\njStat.extend({\n // 2 parameter lists\n // (value, mean, sd, n)\n // (value, array)\n tscore: function tscore() {\n var args = slice.call(arguments);\n return (args.length === 4) ?\n ((args[0] - args[1]) / (args[2] / Math.sqrt(args[3]))) :\n ((args[0] - jStat.mean(args[1])) /\n (jStat.stdev(args[1], true) / Math.sqrt(args[1].length)));\n },\n\n // 3 different paramter lists:\n // (value, mean, sd, n, sides)\n // (tscore, n, sides)\n // (value, array, sides)\n ttest: function ttest() {\n var args = slice.call(arguments);\n var tscore;\n if (args.length === 5) {\n tscore = Math.abs(jStat.tscore(args[0], args[1], args[2], args[3]));\n return (args[4] === 1) ?\n (jStat.studentt.cdf(-tscore, args[3]-1)) :\n (jStat.studentt.cdf(-tscore, args[3]-1)*2);\n }\n if (isNumber(args[1])) {\n tscore = Math.abs(args[0])\n return (args[2] == 1) ?\n (jStat.studentt.cdf(-tscore, args[1]-1)) :\n (jStat.studentt.cdf(-tscore, args[1]-1) * 2);\n }\n tscore = Math.abs(jStat.tscore(args[0], args[1]))\n return (args[2] == 1) ?\n (jStat.studentt.cdf(-tscore, args[1].length-1)) :\n (jStat.studentt.cdf(-tscore, args[1].length-1) * 2);\n }\n});\n\njStat.extend(jStat.fn, {\n tscore: function tscore(value) {\n return (value - this.mean()) / (this.stdev(true) / Math.sqrt(this.cols()));\n },\n\n ttest: function ttest(value, sides) {\n return (sides === 1) ?\n (1 - jStat.studentt.cdf(Math.abs(this.tscore(value)), this.cols()-1)) :\n (jStat.studentt.cdf(-Math.abs(this.tscore(value)), this.cols()-1)*2);\n }\n});\n\n// F Statistics\njStat.extend({\n // Paramter list is as follows:\n // (array1, array2, array3, ...)\n // or it is an array of arrays\n // array of arrays conversion\n anovafscore: function anovafscore() {\n var args = slice.call(arguments),\n expVar, sample, sampMean, sampSampMean, tmpargs, unexpVar, i, j;\n if (args.length === 1) {\n tmpargs = new Array(args[0].length);\n for (i = 0; i < args[0].length; i++) {\n tmpargs[i] = args[0][i];\n }\n args = tmpargs;\n }\n // Builds sample array\n sample = new Array();\n for (i = 0; i < args.length; i++) {\n sample = sample.concat(args[i]);\n }\n sampMean = jStat.mean(sample);\n // Computes the explained variance\n expVar = 0;\n for (i = 0; i < args.length; i++) {\n expVar = expVar + args[i].length * Math.pow(jStat.mean(args[i]) - sampMean, 2);\n }\n expVar /= (args.length - 1);\n // Computes unexplained variance\n unexpVar = 0;\n for (i = 0; i < args.length; i++) {\n sampSampMean = jStat.mean(args[i]);\n for (j = 0; j < args[i].length; j++) {\n unexpVar += Math.pow(args[i][j] - sampSampMean, 2);\n }\n }\n unexpVar /= (sample.length - args.length);\n return expVar / unexpVar;\n },\n\n // 2 different paramter setups\n // (array1, array2, array3, ...)\n // (anovafscore, df1, df2)\n anovaftest: function anovaftest() {\n var args = slice.call(arguments),\n df1, df2, n, i;\n if (isNumber(args[0])) {\n return 1 - jStat.centralF.cdf(args[0], args[1], args[2]);\n }\n var anovafscore = jStat.anovafscore(args);\n df1 = args.length - 1;\n n = 0;\n for (i = 0; i < args.length; i++) {\n n = n + args[i].length;\n }\n df2 = n - df1 - 1;\n return 1 - jStat.centralF.cdf(anovafscore, df1, df2);\n },\n\n ftest: function ftest(fscore, df1, df2) {\n return 1 - jStat.centralF.cdf(fscore, df1, df2);\n }\n});\n\njStat.extend(jStat.fn, {\n anovafscore: function anovafscore() {\n return jStat.anovafscore(this.toArray());\n },\n\n anovaftes: function anovaftes() {\n var n = 0;\n var i;\n for (i = 0; i < this.length; i++) {\n n = n + this[i].length;\n }\n return jStat.ftest(this.anovafscore(), this.length - 1, n - this.length);\n }\n});\n\n// Tukey's range test\njStat.extend({\n // 2 parameter lists\n // (mean1, mean2, n1, n2, sd)\n // (array1, array2, sd)\n qscore: function qscore() {\n var args = slice.call(arguments);\n var mean1, mean2, n1, n2, sd;\n if (isNumber(args[0])) {\n mean1 = args[0];\n mean2 = args[1];\n n1 = args[2];\n n2 = args[3];\n sd = args[4];\n } else {\n mean1 = jStat.mean(args[0]);\n mean2 = jStat.mean(args[1]);\n n1 = args[0].length;\n n2 = args[1].length;\n sd = args[2];\n }\n return Math.abs(mean1 - mean2) / (sd * Math.sqrt((1 / n1 + 1 / n2) / 2));\n },\n\n // 3 different parameter lists:\n // (qscore, n, k)\n // (mean1, mean2, n1, n2, sd, n, k)\n // (array1, array2, sd, n, k)\n qtest: function qtest() {\n var args = slice.call(arguments);\n\n var qscore;\n if (args.length === 3) {\n qscore = args[0];\n args = args.slice(1);\n } else if (args.length === 7) {\n qscore = jStat.qscore(args[0], args[1], args[2], args[3], args[4]);\n args = args.slice(5);\n } else {\n qscore = jStat.qscore(args[0], args[1], args[2]);\n args = args.slice(3);\n }\n\n var n = args[0];\n var k = args[1];\n\n return 1 - jStat.tukey.cdf(qscore, k, n - k);\n },\n\n tukeyhsd: function tukeyhsd(arrays) {\n var sd = jStat.pooledstdev(arrays);\n var means = arrays.map(function (arr) {return jStat.mean(arr);});\n var n = arrays.reduce(function (n, arr) {return n + arr.length;}, 0);\n\n var results = [];\n for (var i = 0; i < arrays.length; ++i) {\n for (var j = i + 1; j < arrays.length; ++j) {\n var p = jStat.qtest(means[i], means[j], arrays[i].length, arrays[j].length, sd, n, arrays.length);\n results.push([[i, j], p]);\n }\n }\n\n return results;\n }\n});\n\n// Error Bounds\njStat.extend({\n // 2 different parameter setups\n // (value, alpha, sd, n)\n // (value, alpha, array)\n normalci: function normalci() {\n var args = slice.call(arguments),\n ans = new Array(2),\n change;\n if (args.length === 4) {\n change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *\n args[2] / Math.sqrt(args[3]));\n } else {\n change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *\n jStat.stdev(args[2]) / Math.sqrt(args[2].length));\n }\n ans[0] = args[0] - change;\n ans[1] = args[0] + change;\n return ans;\n },\n\n // 2 different parameter setups\n // (value, alpha, sd, n)\n // (value, alpha, array)\n tci: function tci() {\n var args = slice.call(arguments),\n ans = new Array(2),\n change;\n if (args.length === 4) {\n change = Math.abs(jStat.studentt.inv(args[1] / 2, args[3] - 1) *\n args[2] / Math.sqrt(args[3]));\n } else {\n change = Math.abs(jStat.studentt.inv(args[1] / 2, args[2].length - 1) *\n jStat.stdev(args[2], true) / Math.sqrt(args[2].length));\n }\n ans[0] = args[0] - change;\n ans[1] = args[0] + change;\n return ans;\n },\n\n significant: function significant(pvalue, alpha) {\n return pvalue < alpha;\n }\n});\n\njStat.extend(jStat.fn, {\n normalci: function normalci(value, alpha) {\n return jStat.normalci(value, alpha, this.toArray());\n },\n\n tci: function tci(value, alpha) {\n return jStat.tci(value, alpha, this.toArray());\n }\n});\n\n// internal method for calculating the z-score for a difference of proportions test\nfunction differenceOfProportions(p1, n1, p2, n2) {\n if (p1 > 1 || p2 > 1 || p1 <= 0 || p2 <= 0) {\n throw new Error(\"Proportions should be greater than 0 and less than 1\")\n }\n var pooled = (p1 * n1 + p2 * n2) / (n1 + n2);\n var se = Math.sqrt(pooled * (1 - pooled) * ((1/n1) + (1/n2)));\n return (p1 - p2) / se;\n}\n\n// Difference of Proportions\njStat.extend(jStat.fn, {\n oneSidedDifferenceOfProportions: function oneSidedDifferenceOfProportions(p1, n1, p2, n2) {\n var z = differenceOfProportions(p1, n1, p2, n2);\n return jStat.ztest(z, 1);\n },\n\n twoSidedDifferenceOfProportions: function twoSidedDifferenceOfProportions(p1, n1, p2, n2) {\n var z = differenceOfProportions(p1, n1, p2, n2);\n return jStat.ztest(z, 2);\n }\n});\n\n}(jStat, Math));\njStat.models = (function(){\n function sub_regress(exog) {\n var var_count = exog[0].length;\n var modelList = jStat.arange(var_count).map(function(endog_index) {\n var exog_index =\n jStat.arange(var_count).filter(function(i){return i!==endog_index});\n return ols(jStat.col(exog, endog_index).map(function(x){ return x[0] }),\n jStat.col(exog, exog_index))\n });\n return modelList;\n }\n\n // do OLS model regress\n // exog have include const columns ,it will not generate it .In fact, exog is\n // \"design matrix\" look at\n //https://en.wikipedia.org/wiki/Design_matrix\n function ols(endog, exog) {\n var nobs = endog.length;\n var df_model = exog[0].length - 1;\n var df_resid = nobs-df_model - 1;\n var coef = jStat.lstsq(exog, endog);\n var predict =\n jStat.multiply(exog, coef.map(function(x) { return [x] }))\n .map(function(p) { return p[0] });\n var resid = jStat.subtract(endog, predict);\n var ybar = jStat.mean(endog);\n // constant cause problem\n // var SST = jStat.sum(endog.map(function(y) {\n // return Math.pow(y-ybar,2);\n // }));\n var SSE = jStat.sum(predict.map(function(f) {\n return Math.pow(f - ybar, 2);\n }));\n var SSR = jStat.sum(endog.map(function(y, i) {\n return Math.pow(y - predict[i], 2);\n }));\n var SST = SSE + SSR;\n var R2 = (SSE / SST);\n return {\n exog:exog,\n endog:endog,\n nobs:nobs,\n df_model:df_model,\n df_resid:df_resid,\n coef:coef,\n predict:predict,\n resid:resid,\n ybar:ybar,\n SST:SST,\n SSE:SSE,\n SSR:SSR,\n R2:R2\n };\n }\n\n // H0: b_I=0\n // H1: b_I!=0\n function t_test(model) {\n var subModelList = sub_regress(model.exog);\n //var sigmaHat=jStat.stdev(model.resid);\n var sigmaHat = Math.sqrt(model.SSR / (model.df_resid));\n var seBetaHat = subModelList.map(function(mod) {\n var SST = mod.SST;\n var R2 = mod.R2;\n return sigmaHat / Math.sqrt(SST * (1 - R2));\n });\n var tStatistic = model.coef.map(function(coef, i) {\n return (coef - 0) / seBetaHat[i];\n });\n var pValue = tStatistic.map(function(t) {\n var leftppf = jStat.studentt.cdf(t, model.df_resid);\n return (leftppf > 0.5 ? 1 - leftppf : leftppf) * 2;\n });\n var c = jStat.studentt.inv(0.975, model.df_resid);\n var interval95 = model.coef.map(function(coef, i) {\n var d = c * seBetaHat[i];\n return [coef - d, coef + d];\n })\n return {\n se: seBetaHat,\n t: tStatistic,\n p: pValue,\n sigmaHat: sigmaHat,\n interval95: interval95\n };\n }\n\n function F_test(model) {\n var F_statistic =\n (model.R2 / model.df_model) / ((1 - model.R2) / model.df_resid);\n var fcdf = function(x, n1, n2) {\n return jStat.beta.cdf(x / (n2 / n1 + x), n1 / 2, n2 / 2)\n }\n var pvalue = 1 - fcdf(F_statistic, model.df_model, model.df_resid);\n return { F_statistic: F_statistic, pvalue: pvalue };\n }\n\n function ols_wrap(endog, exog) {\n var model = ols(endog,exog);\n var ttest = t_test(model);\n var ftest = F_test(model);\n // Provide the Wherry / Ezekiel / McNemar / Cohen Adjusted R^2\n // Which matches the 'adjusted R^2' provided by R's lm package\n var adjust_R2 =\n 1 - (1 - model.R2) * ((model.nobs - 1) / (model.df_resid));\n model.t = ttest;\n model.f = ftest;\n model.adjust_R2 = adjust_R2;\n return model;\n }\n\n return { ols: ols_wrap };\n})();\n//To regress, simply build X matrix\n//(append column of 1's) using\n//buildxmatrix and build the Y\n//matrix using buildymatrix\n//(simply the transpose)\n//and run regress.\n\n\n\n//Regressions\n\njStat.extend({\n buildxmatrix: function buildxmatrix(){\n //Parameters will be passed in as such\n //(array1,array2,array3,...)\n //as (x1,x2,x3,...)\n //needs to be (1,x1,x2,x3,...)\n var matrixRows = new Array(arguments.length);\n for(var i=0;i<arguments.length;i++){\n var array = [1];\n matrixRows[i]= array.concat(arguments[i]);\n }\n return jStat(matrixRows);\n\n },\n\n builddxmatrix: function builddxmatrix() {\n //Paramters will be passed in as such\n //([array1,array2,...]\n var matrixRows = new Array(arguments[0].length);\n for(var i=0;i<arguments[0].length;i++){\n var array = [1]\n matrixRows[i]= array.concat(arguments[0][i]);\n }\n return jStat(matrixRows);\n\n },\n\n buildjxmatrix: function buildjxmatrix(jMat) {\n //Builds from jStat Matrix\n var pass = new Array(jMat.length)\n for(var i=0;i<jMat.length;i++){\n pass[i] = jMat[i];\n }\n return jStat.builddxmatrix(pass);\n\n },\n\n buildymatrix: function buildymatrix(array){\n return jStat(array).transpose();\n },\n\n buildjymatrix: function buildjymatrix(jMat){\n return jMat.transpose();\n },\n\n matrixmult: function matrixmult(A,B){\n var i, j, k, result, sum;\n if (A.cols() == B.rows()) {\n if(B.rows()>1){\n result = [];\n for (i = 0; i < A.rows(); i++) {\n result[i] = [];\n for (j = 0; j < B.cols(); j++) {\n sum = 0;\n for (k = 0; k < A.cols(); k++) {\n sum += A.toArray()[i][k] * B.toArray()[k][j];\n }\n result[i][j] = sum;\n }\n }\n return jStat(result);\n }\n result = [];\n for (i = 0; i < A.rows(); i++) {\n result[i] = [];\n for (j = 0; j < B.cols(); j++) {\n sum = 0;\n for (k = 0; k < A.cols(); k++) {\n sum += A.toArray()[i][k] * B.toArray()[j];\n }\n result[i][j] = sum;\n }\n }\n return jStat(result);\n }\n },\n\n //regress and regresst to be fixed\n\n regress: function regress(jMatX,jMatY){\n //print(\"regressin!\");\n //print(jMatX.toArray());\n var innerinv = jStat.xtranspxinv(jMatX);\n //print(innerinv);\n var xtransp = jMatX.transpose();\n var next = jStat.matrixmult(jStat(innerinv),xtransp);\n return jStat.matrixmult(next,jMatY);\n\n },\n\n regresst: function regresst(jMatX,jMatY,sides){\n var beta = jStat.regress(jMatX,jMatY);\n\n var compile = {};\n compile.anova = {};\n var jMatYBar = jStat.jMatYBar(jMatX, beta);\n compile.yBar = jMatYBar;\n var yAverage = jMatY.mean();\n compile.anova.residuals = jStat.residuals(jMatY, jMatYBar);\n\n compile.anova.ssr = jStat.ssr(jMatYBar, yAverage);\n compile.anova.msr = compile.anova.ssr / (jMatX[0].length - 1);\n\n compile.anova.sse = jStat.sse(jMatY, jMatYBar);\n compile.anova.mse =\n compile.anova.sse / (jMatY.length - (jMatX[0].length - 1) - 1);\n\n compile.anova.sst = jStat.sst(jMatY, yAverage);\n compile.anova.mst = compile.anova.sst / (jMatY.length - 1);\n\n compile.anova.r2 = 1 - (compile.anova.sse / compile.anova.sst);\n if (compile.anova.r2 < 0) compile.anova.r2 = 0;\n\n compile.anova.fratio = compile.anova.msr / compile.anova.mse;\n compile.anova.pvalue =\n jStat.anovaftest(compile.anova.fratio,\n jMatX[0].length - 1,\n jMatY.length - (jMatX[0].length - 1) - 1);\n\n compile.anova.rmse = Math.sqrt(compile.anova.mse);\n\n compile.anova.r2adj = 1 - (compile.anova.mse / compile.anova.mst);\n if (compile.anova.r2adj < 0) compile.anova.r2adj = 0;\n\n compile.stats = new Array(jMatX[0].length);\n var covar = jStat.xtranspxinv(jMatX);\n var sds, ts, ps;\n\n for(var i=0; i<beta.length;i++){\n sds=Math.sqrt(compile.anova.mse * Math.abs(covar[i][i]));\n ts= Math.abs(beta[i] / sds);\n ps= jStat.ttest(ts, jMatY.length - jMatX[0].length - 1, sides);\n\n compile.stats[i]=[beta[i], sds, ts, ps];\n }\n\n compile.regress = beta;\n return compile;\n },\n\n xtranspx: function xtranspx(jMatX){\n return jStat.matrixmult(jMatX.transpose(),jMatX);\n },\n\n\n xtranspxinv: function xtranspxinv(jMatX){\n var inner = jStat.matrixmult(jMatX.transpose(),jMatX);\n var innerinv = jStat.inv(inner);\n return innerinv;\n },\n\n jMatYBar: function jMatYBar(jMatX, beta) {\n var yBar = jStat.matrixmult(jMatX, beta);\n return new jStat(yBar);\n },\n\n residuals: function residuals(jMatY, jMatYBar) {\n return jStat.matrixsubtract(jMatY, jMatYBar);\n },\n\n ssr: function ssr(jMatYBar, yAverage) {\n var ssr = 0;\n for(var i = 0; i < jMatYBar.length; i++) {\n ssr += Math.pow(jMatYBar[i] - yAverage, 2);\n }\n return ssr;\n },\n\n sse: function sse(jMatY, jMatYBar) {\n var sse = 0;\n for(var i = 0; i < jMatY.length; i++) {\n sse += Math.pow(jMatY[i] - jMatYBar[i], 2);\n }\n return sse;\n },\n\n sst: function sst(jMatY, yAverage) {\n var sst = 0;\n for(var i = 0; i < jMatY.length; i++) {\n sst += Math.pow(jMatY[i] - yAverage, 2);\n }\n return sst;\n },\n\n matrixsubtract: function matrixsubtract(A,B){\n var ans = new Array(A.length);\n for(var i=0;i<A.length;i++){\n ans[i] = new Array(A[i].length);\n for(var j=0;j<A[i].length;j++){\n ans[i][j]=A[i][j]-B[i][j];\n }\n }\n return jStat(ans);\n }\n});\n // Make it compatible with previous version.\n jStat.jStat = jStat;\n\n return jStat;\n});\n","export var ArrayUtils;\n(function (ArrayUtils) {\n /**\n * Finds indices of element(s) found with the given filter.\n *\n * @export\n * @template T Type of elements in the array.\n * @param {T[]} values Array to search in.\n * @param {(item: T) => boolean} filter Filtering function including an element if it fits a condition.\n * @return {number[]} Idices of elements corresponding the filter.\n */\n function indexesOf(values, filter) {\n const indexes = [];\n for (let i = 0; i < values.length; i++) {\n if (filter(values[i]))\n indexes.push(i);\n }\n return indexes;\n }\n ArrayUtils.indexesOf = indexesOf;\n /**\n * Generates array from a range [begin; end] or [begin; end) if endExclusive.\n *\n * @export\n * @param {number} begin Beginning of the range.\n * @param {number} end End of the range.\n * @param {boolean} [endExclusive=false] Whether to exclude the end of the range.\n * @return {Int32Array} The range between begin and end.\n */\n function genRange(begin, end, endExclusive = false) {\n const nItems = end - begin + (endExclusive ? 0 : 1);\n const series = new Int32Array(nItems);\n for (let i = 0; i < nItems; ++i)\n series[i] = begin + i;\n return series;\n }\n ArrayUtils.genRange = genRange;\n /**\n * Returns order of values as if they are sorted.\n *\n * @export\n * @param {any[]} values Input array.\n * @param {boolean} [reverse=false] Whether to return reversed order.\n * @return {number[]} The order generated.\n */\n function argSort(values, reverse = false) {\n const sortfn = reverse ? (a, b) => (b[0] - a[0]) : (a, b) => (a[0] - b[0]);\n const decor = (v, i) => [v, i]; // set index to value\n const undecor = (a) => a[1]; // leave only index\n const _argsort = (arr) => arr.map(decor).sort(sortfn).map(undecor);\n return _argsort(values);\n }\n ArrayUtils.argSort = argSort;\n})(ArrayUtils || (ArrayUtils = {}));\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJhcnJheS11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLEtBQVcsVUFBVSxDQW9EMUI7QUFwREQsV0FBaUIsVUFBVTtJQUV6Qjs7Ozs7Ozs7T0FRRztJQUNILFNBQWdCLFNBQVMsQ0FBSSxNQUFXLEVBQUUsTUFBNEI7UUFDcEUsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ25CLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDdkMsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNuQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3BCLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBUGUsb0JBQVMsWUFPeEIsQ0FBQTtJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsU0FBZ0IsUUFBUSxDQUFDLEtBQWEsRUFBRSxHQUFXLEVBQUUsWUFBWSxHQUFHLEtBQUs7UUFDdkUsTUFBTSxNQUFNLEdBQUcsR0FBRyxHQUFHLEtBQUssR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNwRCxNQUFNLE1BQU0sR0FBRyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxFQUFFLEVBQUUsQ0FBQztZQUM3QixNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQztRQUN4QixPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBTmUsbUJBQVEsV0FNdkIsQ0FBQTtJQUVEOzs7Ozs7O09BT0c7SUFDSCxTQUFnQixPQUFPLENBQUMsTUFBYSxFQUFFLFVBQW1CLEtBQUs7UUFDN0QsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQVEsRUFBRSxDQUFRLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQVEsRUFBRSxDQUFRLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3ZHLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBTSxFQUFFLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxxQkFBcUI7UUFDbEUsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFRLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLG1CQUFtQjtRQUN2RCxNQUFNLFFBQVEsR0FBRyxDQUFDLEdBQVUsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFFLE9BQU8sUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFOZSxrQkFBTyxVQU10QixDQUFBO0FBQ0gsQ0FBQyxFQXBEZ0IsVUFBVSxLQUFWLFVBQVUsUUFvRDFCIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IG5hbWVzcGFjZSBBcnJheVV0aWxzIHtcblxuICAvKipcbiAgICogRmluZHMgaW5kaWNlcyBvZiBlbGVtZW50KHMpIGZvdW5kIHdpdGggdGhlIGdpdmVuIGZpbHRlci5cbiAgICpcbiAgICogQGV4cG9ydFxuICAgKiBAdGVtcGxhdGUgVCBUeXBlIG9mIGVsZW1lbnRzIGluIHRoZSBhcnJheS5cbiAgICogQHBhcmFtIHtUW119IHZhbHVlcyBBcnJheSB0byBzZWFyY2ggaW4uXG4gICAqIEBwYXJhbSB7KGl0ZW06IFQpID0+IGJvb2xlYW59IGZpbHRlciBGaWx0ZXJpbmcgZnVuY3Rpb24gaW5jbHVkaW5nIGFuIGVsZW1lbnQgaWYgaXQgZml0cyBhIGNvbmRpdGlvbi5cbiAgICogQHJldHVybiB7bnVtYmVyW119IElkaWNlcyBvZiBlbGVtZW50cyBjb3JyZXNwb25kaW5nIHRoZSBmaWx0ZXIuXG4gICAqL1xuICBleHBvcnQgZnVuY3Rpb24gaW5kZXhlc09mPFQ+KHZhbHVlczogVFtdLCBmaWx0ZXI6IChpdGVtOiBUKSA9PiBib29sZWFuKTogbnVtYmVyW10ge1xuICAgIGNvbnN0IGluZGV4ZXMgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZhbHVlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGZpbHRlcih2YWx1ZXNbaV0pKVxuICAgICAgICBpbmRleGVzLnB1c2goaSk7XG4gICAgfVxuICAgIHJldHVybiBpbmRleGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhcnJheSBmcm9tIGEgcmFuZ2UgW2JlZ2luOyBlbmRdIG9yIFtiZWdpbjsgZW5kKSBpZiBlbmRFeGNsdXNpdmUuXG4gICAqXG4gICAqIEBleHBvcnRcbiAgICogQHBhcmFtIHtudW1iZXJ9IGJlZ2luIEJlZ2lubmluZyBvZiB0aGUgcmFuZ2UuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBlbmQgRW5kIG9mIHRoZSByYW5nZS5cbiAgICogQHBhcmFtIHtib29sZWFufSBbZW5kRXhjbHVzaXZlPWZhbHNlXSBXaGV0aGVyIHRvIGV4Y2x1ZGUgdGhlIGVuZCBvZiB0aGUgcmFuZ2UuXG4gICAqIEByZXR1cm4ge0ludDMyQXJyYXl9IFRoZSByYW5nZSBiZXR3ZWVuIGJlZ2luIGFuZCBlbmQuXG4gICAqL1xuICBleHBvcnQgZnVuY3Rpb24gZ2VuUmFuZ2UoYmVnaW46IG51bWJlciwgZW5kOiBudW1iZXIsIGVuZEV4Y2x1c2l2ZSA9IGZhbHNlKTogSW50MzJBcnJheSB7XG4gICAgY29uc3Qgbkl0ZW1zID0gZW5kIC0gYmVnaW4gKyAoZW5kRXhjbHVzaXZlID8gMCA6IDEpO1xuICAgIGNvbnN0IHNlcmllcyA9IG5ldyBJbnQzMkFycmF5KG5JdGVtcyk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuSXRlbXM7ICsraSlcbiAgICAgIHNlcmllc1tpXSA9IGJlZ2luICsgaTtcbiAgICByZXR1cm4gc2VyaWVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgb3JkZXIgb2YgdmFsdWVzIGFzIGlmIHRoZXkgYXJlIHNvcnRlZC5cbiAgICpcbiAgICogQGV4cG9ydFxuICAgKiBAcGFyYW0ge2FueVtdfSB2YWx1ZXMgSW5wdXQgYXJyYXkuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3JldmVyc2U9ZmFsc2VdIFdoZXRoZXIgdG8gcmV0dXJuIHJldmVyc2VkIG9yZGVyLlxuICAgKiBAcmV0dXJuIHtudW1iZXJbXX0gVGhlIG9yZGVyIGdlbmVyYXRlZC5cbiAgICovXG4gIGV4cG9ydCBmdW5jdGlvbiBhcmdTb3J0KHZhbHVlczogYW55W10sIHJldmVyc2U6IGJvb2xlYW4gPSBmYWxzZSk6IG51bWJlcltdIHtcbiAgICBjb25zdCBzb3J0Zm4gPSByZXZlcnNlID8gKGE6IGFueVtdLCBiOiBhbnlbXSkgPT4gKGJbMF0gLSBhWzBdKSA6IChhOiBhbnlbXSwgYjogYW55W10pID0+IChhWzBdIC0gYlswXSk7XG4gICAgY29uc3QgZGVjb3IgPSAodjogYW55LCBpOiBudW1iZXIpID0+IFt2LCBpXTsgLy8gc2V0IGluZGV4IHRvIHZhbHVlXG4gICAgY29uc3QgdW5kZWNvciA9IChhOiBhbnlbXSkgPT4gYVsxXTsgLy8gbGVhdmUgb25seSBpbmRleFxuICAgIGNvbnN0IF9hcmdzb3J0ID0gKGFycjogYW55W10pID0+IGFyci5tYXAoZGVjb3IpLnNvcnQoc29ydGZuKS5tYXAodW5kZWNvcik7XG4gICAgcmV0dXJuIF9hcmdzb3J0KHZhbHVlcyk7XG4gIH1cbn1cbiJdfQ==","//@ts-ignore: no types\nimport * as jStat from 'jstat';\nexport function tTest(sample1, sample2, devKnown = false, devEqual = false) {\n if (sample1.length <= 1 || sample2.length <= 1)\n throw new Error(`StatisticsError: Wrong sample size; expected at least 2, got ${Math.min(sample1.length, sample2.length)})`);\n const mean1 = jStat.mean(sample1);\n const mean2 = jStat.mean(sample2);\n const variance1 = jStat.variance(sample1);\n const variance2 = jStat.variance(sample2);\n const length1 = sample1.length;\n const length2 = sample2.length;\n let pMore;\n let pLess;\n let pTot;\n if (!devKnown) {\n if (!devEqual) {\n const sampleVariance1 = variance1 / length1;\n const sampleVariance2 = variance2 / length2;\n const criticalValue = (mean1 - mean2) / Math.sqrt(sampleVariance1 + sampleVariance2);\n const dof = Math.pow((sampleVariance1 + sampleVariance2), 2) /\n (Math.pow(sampleVariance1, 2) / (length1 - 1) + Math.pow(sampleVariance2, 2) / (length2 - 1));\n pLess = jStat.studentt.cdf(criticalValue, dof);\n pMore = 1 - pLess;\n pTot = 2 * (pLess < pMore ? pLess : pMore);\n }\n else {\n const dof = length1 + length2 - 2;\n const totalVariance = (variance1 * (length1 - 1) + variance2 * (length2 - 1)) / dof;\n const criticalValue = Math.sqrt(length1 * length2 / (length1 + length2)) * (mean1 - mean2) / totalVariance;\n pMore = 1 - jStat.studentt.cdf(criticalValue, dof);\n pLess = jStat.studentt.cdf(criticalValue, dof);\n pTot = 2 * (pLess < pMore ? pLess : pMore);\n }\n }\n else {\n const sampleVariance1 = variance1 / length1;\n const sampleVariance2 = variance2 / length2;\n const criticalValue = (mean1 - mean2) / Math.sqrt(sampleVariance1 + sampleVariance2);\n pLess = jStat.normal.pdf(criticalValue, 0, 1);\n pMore = 1 - pLess;\n pTot = 2 * (pLess < pMore ? pLess : pMore);\n }\n return { 'p-value': pTot, 'Mean difference': mean1 - mean2, 'p-value more': pMore, 'p-value less': pLess };\n}\nexport function uTest(x, y, continuity = true) {\n const xy = x.concat(y);\n const n1 = x.length;\n const n2 = y.length;\n const med1 = jStat.median(x);\n const med2 = jStat.median(y);\n const ranks = jStat.rank(xy);\n const R1 = jStat.sum(ranks.slice(0, n1));\n const U1 = R1 - n1 * (n1 + 1) / 2;\n const U2 = n1 * n2 - U1;\n const U = U1 > U2 ? U1 : U2;\n const mu = n1 * n2 / 2;\n const n = n1 + n2;\n const tieTerm = _tieTerm(ranks);\n const s = Math.sqrt(n1 * n2 / 12 * ((n + 1) - tieTerm / (n * (n - 1))));\n let numerator = U - mu;\n if (continuity)\n numerator -= 0.5;\n const z = numerator / s;\n const p = 2 * (1 - jStat.normal.cdf(z, 0, 1));\n return { 'p-value': p, 'Median difference': med1 - med2, 'p-value more': p, 'p-value less': p };\n}\nfunction _tieTerm(ranks) {\n const ties = {};\n ranks.forEach((num) => {\n ties[num] = (ties[num] || 0) + 1;\n });\n return jStat.sum(Object.values(ties));\n}\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0ZXN0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxzQkFBc0I7QUFDdEIsT0FBTyxLQUFLLEtBQUssTUFBTSxPQUFPLENBQUM7QUFZL0IsTUFBTSxVQUFVLEtBQUssQ0FBQyxPQUFtQixFQUFFLE9BQW1CLEVBQUUsUUFBUSxHQUFDLEtBQUssRUFBRSxRQUFRLEdBQUMsS0FBSztJQUM1RixJQUFJLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQztRQUM1QyxNQUFNLElBQUksS0FBSyxDQUFDLGdFQUFnRSxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUUvSCxNQUFNLEtBQUssR0FBVyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFDLE1BQU0sS0FBSyxHQUFXLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDMUMsTUFBTSxTQUFTLEdBQVcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNsRCxNQUFNLFNBQVMsR0FBVyxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2xELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDL0IsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztJQUUvQixJQUFJLEtBQUssQ0FBQztJQUNWLElBQUksS0FBSyxDQUFDO0lBQ1YsSUFBSSxJQUFJLENBQUM7SUFFVCxJQUFJLENBQUMsUUFBUSxFQUFFO1FBQ2IsSUFBSSxDQUFDLFFBQVEsRUFBRTtZQUNiLE1BQU0sZUFBZSxHQUFHLFNBQVMsR0FBRyxPQUFPLENBQUM7WUFDNUMsTUFBTSxlQUFlLEdBQUcsU0FBUyxHQUFHLE9BQU8sQ0FBQztZQUM1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O0lBQ3BCLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDcEIsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3QixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTdCLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFN0IsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xDLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQ3hCLE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBRTVCLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZCLE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7SUFFbEIsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxPQUFPLEdBQUcsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFdkUsSUFBSSxTQUFTLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUV2QixJQUFJLFVBQVU7UUFDWixTQUFTLElBQUksR0FBRyxDQUFDO0lBR25CLE1BQU0sQ0FBQyxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUM7SUFFeEIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU5QyxPQUFPLEVBQUMsU0FBUyxFQUFFLENBQUMsRUFBRSxtQkFBbUIsRUFBRSxJQUFJLEdBQUcsSUFBSSxFQUFFLGNBQWMsRUFBRSxDQUFDLEVBQUUsY0FBYyxFQUFFLENBQUMsRUFBQyxDQUFDO0FBQ2hHLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBQyxLQUFlO0lBQy9CLE1BQU0sSUFBSSxHQUE0QixFQUFFLENBQUM7SUFFekMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1FBQ3BCLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDbkMsQ0FBQyxDQUFDLENBQUM7SUFFSCxPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0FBQ3hDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvL0B0cy1pZ25vcmU6IG5vIHR5cGVzXG5pbXBvcnQgKiBhcyBqU3RhdCBmcm9tICdqc3RhdCc7XG5cbnR5cGUgdGVzdFN0YXRzID0ge1xuICAncC12YWx1ZSc6IG51bWJlcixcbiAgJ01lYW4gZGlmZmVyZW5jZSc/OiBudW1iZXIsXG4gICdNZWRpYW4gZGlmZmVyZW5jZSc/OiBudW1iZXIsXG4gICdwLXZhbHVlIG1vcmUnOiBudW1iZXIsXG4gICdwLXZhbHVlIGxlc3MnOiBudW1iZXIsXG59O1xuXG50eXBlIFBvcHVsYXRpb24gPSBudW1iZXJbXSB8IEZsb2F0MzJBcnJheSB8IEludDMyQXJyYXk7XG5cbmV4cG9ydCBmdW5jdGlvbiB0VGVzdChzYW1wbGUxOiBQb3B1bGF0aW9uLCBzYW1wbGUyOiBQb3B1bGF0aW9uLCBkZXZLbm93bj1mYWxzZSwgZGV2RXF1YWw9ZmFsc2UpOiB0ZXN0U3RhdHMge1xuICBpZiAoc2FtcGxlMS5sZW5ndGggPD0gMSB8fCBzYW1wbGUyLmxlbmd0aCA8PSAxKVxuICAgIHRocm93IG5ldyBFcnJvcihgU3RhdGlzdGljc0Vycm9yOiBXcm9uZyBzYW1wbGUgc2l6ZTsgZXhwZWN0ZWQgYXQgbGVhc3QgMiwgZ290ICR7TWF0aC5taW4oc2FtcGxlMS5sZW5ndGgsIHNhbXBsZTIubGVuZ3RoKX0pYCk7XG5cbiAgY29uc3QgbWVhbjE6IG51bWJlciA9IGpTdGF0Lm1lYW4oc2FtcGxlMSk7XG4gIGNvbnN0IG1lYW4yOiBudW1iZXIgPSBqU3RhdC5tZWFuKHNhbXBsZTIpO1xuICBjb25zdCB2YXJpYW5jZTE6IG51bWJlciA9IGpTdGF0LnZhcmlhbmNlKHNhbXBsZTEpO1xuICBjb25zdCB2YXJpYW5jZTI6IG51bWJlciA9IGpTdGF0LnZhcmlhbmNlKHNhbXBsZTIpO1xuICBjb25zdCBsZW5ndGgxID0gc2FtcGxlMS5sZW5ndGg7XG4gIGNvbnN0IGxlbmd0aDIgPSBzYW1wbGUyLmxlbmd0aDtcblxuICBsZXQgcE1vcmU7XG4gIGxldCBwTGVzcztcbiAgbGV0IHBUb3Q7XG5cbiAgaWYgKCFkZXZLbm93bikge1xuICAgIGlmICghZGV2RXF1YWwpIHtcbiAgICAgIGNvbnN0IHNhbXBsZVZhcmlhbmNlMSA9IHZhcmlhbmNlMSAvIGxlbmd0aDE7XG4gICAgICBjb25zdCBzYW1wbGVWYXJpYW5jZTIgPSB2YXJpYW5jZTIgLyBsZW5ndGgyO1xuICAgICAgY29uc3QgY3JpdGljYWxWYWx1ZSA9IChtZWFuMSAtIG1lYW4yKSAvIE1hdGguc3FydChzYW1wbGVWYXJpYW5jZTEgKyBzYW1wbGVWYXJpYW5jZTIpO1xuICAgICAgY29uc3QgZG9mID0gTWF0aC5wb3coKHNhbXBsZVZhcmlhbmNlMSArIHNhbXBsZVZhcmlhbmNlMiksIDIpIC9cbiAgICAgICAgKE1hdGgucG93KHNhbXBsZVZhcmlhbmNlMSwgMikgLyAobGVuZ3RoMSAtIDEpICsgTWF0aC5wb3coc2FtcGxlVmFyaWFuY2UyLCAyKSAvIChsZW5ndGgyIC0gMSkpO1xuXG4gICAgICBwTGVzcyA9IGpTdGF0LnN0dWRlbnR0LmNkZihjcml0aWNhbFZhbHVlLCBkb2YpO1xuICAgICAgcE1vcmUgPSAxIC0gcExlc3M7XG4gICAgICBwVG90ID0gMiAqIChwTGVzcyA8IHBNb3JlID8gcExlc3MgOiBwTW9yZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGRvZiA9IGxlbmd0aDEgKyBsZW5ndGgyIC0gMjtcbiAgICAgIGNvbnN0IHRvdGFsVmFyaWFuY2UgPSAodmFyaWFuY2UxICogKGxlbmd0aDEgLSAxKSArIHZhcmlhbmNlMiAqIChsZW5ndGgyIC0gMSkpIC8gZG9mO1xuICAgICAgY29uc3QgY3JpdGljYWxWYWx1ZSA9IE1hdGguc3FydChsZW5ndGgxICogbGVuZ3RoMiAvIChsZW5ndGgxICsgbGVuZ3RoMikpICogKG1lYW4xIC0gbWVhbjIpIC8gdG90YWxWYXJpYW5jZTtcblxuICAgICAgcE1vcmUgPSAxIC0galN0YXQuc3R1ZGVudHQuY2RmKGNyaXRpY2FsVmFsdWUsIGRvZik7XG4gICAgICBwTGVzcyA9IGpTdGF0LnN0dWRlbnR0LmNkZihjcml0aWNhbFZhbHVlLCBkb2YpO1xuICAgICAgcFRvdCA9IDIgKiAocExlc3MgPCBwTW9yZSA/IHBMZXNzIDogcE1vcmUpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBjb25zdCBzYW1wbGVWYXJpYW5jZTEgPSB2YXJpYW5jZTEgLyBsZW5ndGgxO1xuICAgIGNvbnN0IHNhbXBsZVZhcmlhbmNlMiA9IHZhcmlhbmNlMiAvIGxlbmd0aDI7XG4gICAgY29uc3QgY3JpdGljYWxWYWx1ZSA9IChtZWFuMSAtIG1lYW4yKSAvIE1hdGguc3FydChzYW1wbGVWYXJpYW5jZTEgKyBzYW1wbGVWYXJpYW5jZTIpO1xuXG4gICAgcExlc3MgPSBqU3RhdC5ub3JtYWwucGRmKGNyaXRpY2FsVmFsdWUsIDAsIDEpO1xuICAgIHBNb3JlID0gMSAtIHBMZXNzO1xuICAgIHBUb3QgPSAyICogKHBMZXNzIDwgcE1vcmUgPyBwTGVzcyA6IHBNb3JlKTtcbiAgfVxuICByZXR1cm4geydwLXZhbHVlJzogcFRvdCwgJ01lYW4gZGlmZmVyZW5jZSc6IG1lYW4xIC0gbWVhbjIsICdwLXZhbHVlIG1vcmUnOiBwTW9yZSwgJ3AtdmFsdWUgbGVzcyc6IHBMZXNzfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHVUZXN0KHg6IG51bWJlcltdLCB5OiBudW1iZXJbXSwgY29udGludWl0eT10cnVlKTogdGVzdFN0YXRzIHtcbiAgY29uc3QgeHkgPSB4LmNvbmNhdCh5KTtcbiAgY29uc3QgbjEgPSB4Lmxlbmd0aDtcbiAgY29uc3QgbjIgPSB5Lmxlbmd0aDtcbiAgY29uc3QgbWVkMSA9IGpTdGF0Lm1lZGlhbih4KTtcbiAgY29uc3QgbWVkMiA9IGpTdGF0Lm1lZGlhbih5KTtcblxuICBjb25zdCByYW5rcyA9IGpTdGF0LnJhbmsoeHkpO1xuXG4gIGNvbnN0IFIxID0galN0YXQuc3VtKHJhbmtzLnNsaWNlKDAsIG4xKSk7XG4gIGNvbnN0IFUxID0gUjEgLSBuMSAqIChuMSArIDEpIC8gMjtcbiAgY29uc3QgVTIgPSBuMSAqIG4yIC0gVTE7XG4gIGNvbnN0IFUgPSBVMSA+IFUyID8gVTEgOiBVMjtcblxuICBjb25zdCBtdSA9IG4xICogbjIgLyAyO1xuICBjb25zdCBuID0gbjEgKyBuMjtcblxuICBjb25zdCB0aWVUZXJtID0gX3RpZVRlcm0ocmFua3MpO1xuICBjb25zdCBzID0gTWF0aC5zcXJ0KG4xICogbjIgLyAxMiAqICgobiArIDEpIC0gdGllVGVybSAvIChuKiAobiAtIDEpKSkpO1xuXG4gIGxldCBudW1lcmF0b3IgPSBVIC0gbXU7XG5cbiAgaWYgKGNvbnRpbnVpdHkpXG4gICAgbnVtZXJhdG9yIC09IDAuNTtcblxuXG4gIGNvbnN0IHogPSBudW1lcmF0b3IgLyBzO1xuXG4gIGNvbnN0IHAgPSAyICogKDEgLSBqU3RhdC5ub3JtYWwuY2RmKHosIDAsIDEpKTtcblxuICByZXR1cm4geydwLXZhbHVlJzogcCwgJ01lZGlhbiBkaWZmZXJlbmNlJzogbWVkMSAtIG1lZDIsICdwLXZhbHVlIG1vcmUnOiBwLCAncC12YWx1ZSBsZXNzJzogcH07XG59XG5cbmZ1bmN0aW9uIF90aWVUZXJtKHJhbmtzOiBudW1iZXJbXSk6IG51bWJlciB7XG4gIGNvbnN0IHRpZXM6IHtba2V5OiBudW1iZXJdOiBudW1iZXJ9ID0ge307XG5cbiAgcmFua3MuZm9yRWFjaCgobnVtKSA9PiB7XG4gICAgdGllc1tudW1dID0gKHRpZXNbbnVtXSB8fCAwKSArIDE7XG4gIH0pO1xuXG4gIHJldHVybiBqU3RhdC5zdW0oT2JqZWN0LnZhbHVlcyh0aWVzKSk7XG59XG4iXX0=","import { ArrayUtils } from '@datagrok-libraries/utils/src/array-utils';\n/** @type {*} A dictionary of basic binary operations. */\nconst _operations = {\n '+': (a, b) => (a + b),\n '-': (a, b) => (a - b),\n '*': (a, b) => (a * b),\n '/': (a, b) => (a / b),\n 'min': (a, b) => (a < b ? a : b),\n 'max': (a, b) => (a > b ? a : b),\n};\n/**\n * Returns the indices that would sort an array.\n *\n * @param {Float32Array} values Array to sort.\n * @return {Int32Array} Array of indices that sort values along the first axis.\n */\nfunction _argsort(values) {\n const array = Array.from(values);\n return Int32Array.from(ArrayUtils.argSort(array));\n}\n/**\n * Take elements from an array.\n *\n * @param {Int32Array} order The indices of the values to extract.\n * @param {Float32Array} values The source array.\n * @return {Float32Array} The returned array has the same type as values.\n */\nfunction _take(order, values) {\n // TODO: Implement a general function for TypedArray.\n return Float32Array.from(values).map((_, i) => values[order[i]]);\n}\n/**\n * Assign elements of an array following the order given (floating-point version).\n *\n * @param {Float32Array} values The source array.\n * @param {Int32Array} order The order given.\n * @return {Float32Array} The returned array has the same type as values.\n */\nfunction _give(values, order) {\n const v = Float32Array.from(values);\n for (let i = 0; i < order.length; ++i)\n v[order[i]] = values[i];\n return v;\n}\n/**\n * Assign elements of an array following the order given (boolean version).\n *\n * @param {Array<boolean>} values The source array.\n * @param {Int32Array} order The order given.\n * @return {Array<boolean>} The returned array has the same type as values.\n */\nfunction _giveb(values, order) {\n const v = Array.from(values);\n for (let i = 0; i < order.length; ++i)\n v[order[i]] = values[i];\n return v;\n}\n/**\n * No frills empirical cdf used in fdrcorrection.\n *\n * @param {Float32Array} x The source array to take a dimension from.\n * @return {Float32Array} Empirical cdf.\n */\nfunction _ecdf(x) {\n const nobs = x.length;\n return Float32Array.from(x).map((_, i) => (i + 1) / nobs);\n}\n/**\n * cm = np.sum(1./np.arange(1, len(pvals_sorted)+1))\n *\n * @param {number} n The number given.\n * @return {number} cm value.\n */\nfunction _cm(n) {\n let sum = 0;\n for (let i = 0; i < n; ++i)\n sum += 1 / (i + 1);\n return sum;\n}\n/**\n * Basic operation under a vector and a scalar.\n *\n * @param {Float32Array} values The source vector.\n * @param {number} scale The scalar.\n * @param {string} [op='*'] The operation to perform.\n * @return {Float32Array} New vector as a result of the operation.\n */\nfunction _factor(values, scale, op = '*') {\n return Float32Array.from(values).map((v, _) => _operations[op](v, scale));\n}\n/**\n * Basic operation under two vectors.\n *\n * @param {Float32Array} values The first vector.\n * @param {Float32Array} scale The second vector.\n * @param {string} [op='*'] The operation to perform.\n * @return {Float32Array} New vector as a result of the operation.\n */\nfunction _vfactor(values, scale, op = '*') {\n return Float32Array.from(values).map((v, i) => _operations[op](v, scale[i]));\n}\n/**\n * Accumulate the result of applying the min operator to all elements.\n *\n * @param {Float32Array} values The array to act on.\n * @return {Float32Array} The accumulated values.\n */\nfunction _minimumAccumulate(values) {\n const nItems = values.length;\n const r = Float32Array.from(values);\n for (let i = 0; i < nItems; ++i)\n r[i] = values.slice(0, i + 1).reduce((a, b, _, __) => (_operations['min'](a, b)));\n return r;\n}\n/**\n * pvalue correction for false discovery rate\n *\n * @export\n * @param {Float32Array} pvals Set of p-values of the individual tests.\n * @param {number} [alpha=0.05] Family-wise error rate. Defaults to 0.05.\n * @param {string} [method='n'] {'i', 'indep', 'p', 'poscorr', 'n', 'negcorr'}, optional\n * Which method to use for FDR correction.\n * ``{'i', 'indep', 'p', 'poscorr'}`` all refer to ``fdr_bh``\n * (Benjamini/Hochberg for independent or positively\n * correlated tests). ``{'n', 'negcorr'}`` both refer to ``fdr_by``\n * (Benjamini/Yekutieli for general or negatively correlated tests).\n * Defaults to 'n'.\n * @param {boolean} [isSorted=false] If False (default), the p_values will be sorted, but the corrected\n * pvalues are in the original order. If True, then it assumed that the\n * pvalues are already sorted in ascending order.\n * @return {[Array<boolean>, Float32Array]} rejected : ndarray, bool\n * True if a hypothesis is rejected, False if not\n * pvalue-corrected : ndarray\n * pvalues adjusted for multiple hypothesis testing to limit FDR\n * @see\n * If there is prior information on the fraction of true hypothesis, then alpha\n * should be set to ``alpha * m/m_0`` where m is the number of tests,\n * given by the p-values, and m_0 is an estimate of the true hypothesis.\n * (see Benjamini, Krieger and Yekuteli)\n *\n * The two-step method of Benjamini, Krieger and Yekutiel that estimates the number\n * of false hypotheses will be available (soon).\n *\n * Both methods exposed via this function (Benjamini/Hochberg, Benjamini/Yekutieli)\n * are also available in the function ``multipletests``, as ``method=\"fdr_bh\"`` and\n * ``method=\"fdr_by\"``, respectively.\n */\nexport function fdrcorrection(pvals, alpha = 0.05, method = 'n', isSorted = false) {\n const nItems = pvals.length;\n let pvalsSorted;\n let pvalsSortind;\n let cm = 0;\n if (!isSorted) {\n pvalsSortind = _argsort(pvals);\n pvalsSorted = _take(pvalsSortind, pvals);\n }\n else {\n pvalsSortind = new Int32Array(nItems).fill(0).map((_, i) => (i));\n pvalsSorted = pvals; // alias\n }\n let ecdffactor = _ecdf(pvalsSorted);\n if (['n', 'negcorr'].includes(method)) {\n cm = _cm(nItems);\n ecdffactor = _factor(ecdffactor, cm, '/');\n }\n else if (!['i', 'indep', 'p', 'poscorr'].includes(method))\n throw new Error('only indep and negcorr implemented');\n const reject = new Array(nItems).fill(false);\n let rejectmax = -1;\n for (let i = 0; i < nItems; ++i) {\n if (pvalsSorted[i] <= ecdffactor[i] * alpha)\n rejectmax = i;\n }\n if (rejectmax >= 0) {\n for (let i = 0; i < rejectmax; ++i)\n reject[i] = true;\n }\n let pvalsCorrected = _vfactor(pvalsSorted, ecdffactor, '/');\n pvalsCorrected = _minimumAccumulate(pvalsCorrected.reverse()).reverse();\n for (let i = 0; i < nItems; ++i) {\n if (pvalsCorrected[i] > 1)\n pvalsCorrected[i] = 1;\n }\n if (!isSorted) {\n const pvalsCorrected_ = _give(pvalsCorrected, pvalsSortind);\n const reject_ = _giveb(reject, pvalsSortind);\n return [reject_, pvalsCorrected_];\n }\n return [reject, pvalsCorrected];\n}\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXVsdGlwbGUtdGVzdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJtdWx0aXBsZS10ZXN0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sMkNBQTJDLENBQUM7QUFFckUseURBQXlEO0FBQ3pELE1BQU0sV0FBVyxHQUErQjtJQUM5QyxHQUFHLEVBQUUsQ0FBQyxDQUFTLEVBQUUsQ0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEMsR0FBRyxFQUFFLENBQUMsQ0FBUyxFQUFFLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RDLEdBQUcsRUFBRSxDQUFDLENBQVMsRUFBRSxDQUFTLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN0QyxHQUFHLEVBQUUsQ0FBQyxDQUFTLEVBQUUsQ0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEMsS0FBSyxFQUFFLENBQUMsQ0FBUyxFQUFFLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRCxLQUFLLEVBQUUsQ0FBQyxDQUFTLEVBQUUsQ0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0NBQ2pELENBQUM7QUFFRjs7Ozs7R0FLRztBQUNILFNBQVMsUUFBUSxDQUFDLE1BQW9CO0lBQ3BDLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDakMsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FB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LEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBRXhFLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLEVBQUUsRUFBRSxDQUFDLEVBQUU7UUFDL0IsSUFBSSxjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztZQUN2QixjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0tBQ3pCO0lBRUQsSUFBSSxDQUFDLFFBQVEsRUFBRTtRQUNiLE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDNUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUM3QyxPQUFPLENBQUMsT0FBTyxFQUFFLGVBQWUsQ0FBQyxDQUFDO0tBQ25DO0lBQ0QsT0FBTyxDQUFDLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQztBQUNsQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtBcnJheVV0aWxzfSBmcm9tICdAZGF0YWdyb2stbGlicmFyaWVzL3V0aWxzL3NyYy9hcnJheS11dGlscyc7XG5cbi8qKiBAdHlwZSB7Kn0gQSBkaWN0aW9uYXJ5IG9mIGJhc2ljIGJpbmFyeSBvcGVyYXRpb25zLiAqL1xuY29uc3QgX29wZXJhdGlvbnM6IHtbbmFtZTogc3RyaW5nXTogRnVuY3Rpb259ID0ge1xuICAnKyc6IChhOiBudW1iZXIsIGI6IG51bWJlcikgPT4gKGEgKyBiKSxcbiAgJy0nOiAoYTogbnVtYmVyLCBiOiBudW1iZXIpID0+IChhIC0gYiksXG4gICcqJzogKGE6IG51bWJlciwgYjogbnVtYmVyKSA9PiAoYSAqIGIpLFxuICAnLyc6IChhOiBudW1iZXIsIGI6IG51bWJlcikgPT4gKGEgLyBiKSxcbiAgJ21pbic6IChhOiBudW1iZXIsIGI6IG51bWJlcikgPT4gKGEgPCBiID8gYSA6IGIpLFxuICAnbWF4JzogKGE6IG51bWJlciwgYjogbnVtYmVyKSA9PiAoYSA+IGIgPyBhIDogYiksXG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGluZGljZXMgdGhhdCB3b3VsZCBzb3J0IGFuIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7RmxvYXQzMkFycmF5fSB2YWx1ZXMgQXJyYXkgdG8gc29ydC5cbiAqIEByZXR1cm4ge0ludDMyQXJyYXl9IEFycmF5IG9mIGluZGljZXMgdGhhdCBzb3J0IHZhbHVlcyBhbG9uZyB0aGUgZmlyc3QgYXhpcy5cbiAqL1xuZnVuY3Rpb24gX2FyZ3NvcnQodmFsdWVzOiBGbG9hdDMyQXJyYXkpOiBJbnQzMkFycmF5IHtcbiAgY29uc3QgYXJyYXkgPSBBcnJheS5mcm9tKHZhbHVlcyk7XG4gIHJldHVybiBJbnQzMkFycmF5LmZyb20oQXJyYXlVdGlscy5hcmdTb3J0KGFycmF5KSk7XG59XG5cbi8qKlxuICogVGFrZSBlbGVtZW50cyBmcm9tIGFuIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7SW50MzJBcnJheX0gb3JkZXIgVGhlIGluZGljZXMgb2YgdGhlIHZhbHVlcyB0byBleHRyYWN0LlxuICogQHBhcmFtIHtGbG9hdDMyQXJyYXl9IHZhbHVlcyBUaGUgc291cmNlIGFycmF5LlxuICogQHJldHVybiB7RmxvYXQzMkFycmF5fSBUaGUgcmV0dXJuZWQgYXJyYXkgaGFzIHRoZSBzYW1lIHR5cGUgYXMgdmFsdWVzLlxuICovXG5mdW5jdGlvbiBfdGFrZShvcmRlcjogSW50MzJBcnJheSwgdmFsdWVzOiBGbG9hdDMyQXJyYXkpOiBGbG9hdDMyQXJyYXkge1xuICAvLyBUT0RPOiBJbXBsZW1lbnQgYSBnZW5lcmFsIGZ1bmN0aW9uIGZvciBUeXBlZEFycmF5LlxuICByZXR1cm4gRmxvYXQzMkFycmF5LmZyb20odmFsdWVzKS5tYXAoKF8sIGkpID0+IHZhbHVlc1tvcmRlcltpXV0pO1xufVxuXG4vKipcbiAqIEFzc2lnbiBlbGVtZW50cyBvZiBhbiBhcnJheSBmb2xsb3dpbmcgdGhlIG9yZGVyIGdpdmVuIChmbG9hdGluZy1wb2ludCB2ZXJzaW9uKS5cbiAqXG4gKiBAcGFyYW0ge0Zsb2F0MzJBcnJheX0gdmFsdWVzIFRoZSBzb3VyY2UgYXJyYXkuXG4gKiBAcGFyYW0ge0ludDMyQXJyYXl9IG9yZGVyIFRoZSBvcmRlciBnaXZlbi5cbiAqIEByZXR1cm4ge0Zsb2F0MzJBcnJheX0gVGhlIHJldHVybmVkIGFycmF5IGhhcyB0aGUgc2FtZSB0eXBlIGFzIHZhbHVlcy5cbiAqL1xuZnVuY3Rpb24gX2dpdmUodmFsdWVzOiBGbG9hdDMyQXJyYXksIG9yZGVyOiBJbnQzMkFycmF5KTogRmxvYXQzMkFycmF5IHtcbiAgY29uc3QgdiA9IEZsb2F0MzJBcnJheS5mcm9tKHZhbHVlcyk7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBvcmRlci5sZW5ndGg7ICsraSlcbiAgICB2W29yZGVyW2ldXSA9IHZhbHVlc1tpXTtcblxuICByZXR1cm4gdjtcbn1cblxuLyoqXG4gKiBBc3NpZ24gZWxlbWVudHMgb2YgYW4gYXJyYXkgZm9sbG93aW5nIHRoZSBvcmRlciBnaXZlbiAoYm9vbGVhbiB2ZXJzaW9uKS5cbiAqXG4gKiBAcGFyYW0ge0FycmF5PGJvb2xlYW4+fSB2YWx1ZXMgVGhlIHNvdXJjZSBhcnJheS5cbiAqIEBwYXJhbSB7SW50MzJBcnJheX0gb3JkZXIgVGhlIG9yZGVyIGdpdmVuLlxuICogQHJldHVybiB7QXJyYXk8Ym9vbGVhbj59IFRoZSByZXR1cm5lZCBhcnJheSBoYXMgdGhlIHNhbWUgdHlwZSBhcyB2YWx1ZXMuXG4gKi9cbmZ1bmN0aW9uIF9naXZlYih2YWx1ZXM6IEFycmF5PGJvb2xlYW4+LCBvcmRlcjogSW50MzJBcnJheSk6IEFycmF5PGJvb2xlYW4+IHtcbiAgY29uc3QgdiA9IEFycmF5LmZyb20odmFsdWVzKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IG9yZGVyLmxlbmd0aDsgKytpKVxuICAgIHZbb3JkZXJbaV1dID0gdmFsdWVzW2ldO1xuXG4gIHJldHVybiB2O1xufVxuXG4vKipcbiAqIE5vIGZyaWxscyBlbXBpcmljYWwgY2RmIHVzZWQgaW4gZmRyY29ycmVjdGlvbi5cbiAqXG4gKiBAcGFyYW0ge0Zsb2F0MzJBcnJheX0geCBUaGUgc291cmNlIGFycmF5IHRvIHRha2UgYSBkaW1lbnNpb24gZnJvbS5cbiAqIEByZXR1cm4ge0Zsb2F0MzJBcnJheX0gRW1waXJpY2FsIGNkZi5cbiAqL1xuZnVuY3Rpb24gX2VjZGYoeDogRmxvYXQzMkFycmF5KTogRmxvYXQzMkFycmF5IHtcbiAgY29uc3Qgbm9icyA9IHgubGVuZ3RoO1xuICByZXR1cm4gRmxvYXQzMkFycmF5LmZyb20oeCkubWFwKChfLCBpKSA9PiAoaSsxKS9ub2JzKTtcbn1cblxuLyoqXG4gKiBjbSA9IG5wLnN1bSgxLi9ucC5hcmFuZ2UoMSwgbGVuKHB2YWxzX3NvcnRlZCkrMSkpXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBnaXZlbi5cbiAqIEByZXR1cm4ge251bWJlcn0gY20gdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIF9jbShuOiBudW1iZXIpOiBudW1iZXIge1xuICBsZXQgc3VtID0gMDtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyArK2kpXG4gICAgc3VtICs9IDEgLyAoaSsxKTtcblxuICByZXR1cm4gc3VtO1xufVxuXG4vKipcbiAqIEJhc2ljIG9wZXJhdGlvbiB1bmRlciBhIHZlY3RvciBhbmQgYSBzY2FsYXIuXG4gKlxuICogQHBhcmFtIHtGbG9hdDMyQXJyYXl9IHZhbHVlcyBUaGUgc291cmNlIHZlY3Rvci5cbiAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsZSBUaGUgc2NhbGFyLlxuICogQHBhcmFtIHtzdHJpbmd9IFtvcD0nKiddIFRoZSBvcGVyYXRpb24gdG8gcGVyZm9ybS5cbiAqIEByZXR1cm4ge0Zsb2F0MzJBcnJheX0gTmV3IHZlY3RvciBhcyBhIHJlc3VsdCBvZiB0aGUgb3BlcmF0aW9uLlxuICovXG5mdW5jdGlvbiBfZmFjdG9yKHZhbHVlczogRmxvYXQzMkFycmF5LCBzY2FsZTogbnVtYmVyLCBvcCA9ICcqJyk6IEZsb2F0MzJBcnJheSB7XG4gIHJldHVybiBGbG9hdDMyQXJyYXkuZnJvbSh2YWx1ZXMpLm1hcCgodiwgXykgPT4gX29wZXJhdGlvbnNbb3BdKHYsIHNjYWxlKSk7XG59XG5cbi8qKlxuICogQmFzaWMgb3BlcmF0aW9uIHVuZGVyIHR3byB2ZWN0b3JzLlxuICpcbiAqIEBwYXJhbSB7RmxvYXQzMkFycmF5fSB2YWx1ZXMgVGhlIGZpcnN0IHZlY3Rvci5cbiAqIEBwYXJhbSB7RmxvYXQzMkFycmF5fSBzY2FsZSBUaGUgc2Vjb25kIHZlY3Rvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3A9JyonXSBUaGUgb3BlcmF0aW9uIHRvIHBlcmZvcm0uXG4gKiBAcmV0dXJuIHtGbG9hdDMyQXJyYXl9IE5ldyB2ZWN0b3IgYXMgYSByZXN1bHQgb2YgdGhlIG9wZXJhdGlvbi5cbiAqL1xuZnVuY3Rpb24gX3ZmYWN0b3IodmFsdWVzOiBGbG9hdDMyQXJyYXksIHNjYWxlOiBGbG9hdDMyQXJyYXksIG9wID0gJyonKTogRmxvYXQzMkFycmF5IHtcbiAgcmV0dXJuIEZsb2F0MzJBcnJheS5mcm9tKHZhbHVlcykubWFwKCh2LCBpKSA9PiBfb3BlcmF0aW9uc1tvcF0odiwgc2NhbGVbaV0pKTtcbn1cblxuLyoqXG4gKiBBY2N1bXVsYXRlIHRoZSByZXN1bHQgb2YgYXBwbHlpbmcgdGhlIG1pbiBvcGVyYXRvciB0byBhbGwgZWxlbWVudHMuXG4gKlxuICogQHBhcmFtIHtGbG9hdDMyQXJyYXl9IHZhbHVlcyBUaGUgYXJyYXkgdG8gYWN0IG9uLlxuICogQHJldHVybiB7RmxvYXQzMkFycmF5fSBUaGUgYWNjdW11bGF0ZWQgdmFsdWVzLlxuICovXG5mdW5jdGlvbiBfbWluaW11bUFjY3VtdWxhdGUodmFsdWVzOiBGbG9hdDMyQXJyYXkpOiBGbG9hdDMyQXJyYXkge1xuICBjb25zdCBuSXRlbXMgPSB2YWx1ZXMubGVuZ3RoO1xuICBjb25zdCByID0gRmxvYXQzMkFycmF5LmZyb20odmFsdWVzKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IG5JdGVtczsgKytpKVxuICAgIHJbaV0gPSB2YWx1ZXMuc2xpY2UoMCwgaSsxKS5yZWR1Y2UoKGEsIGIsIF8sIF9fKSA9PiAoX29wZXJhdGlvbnNbJ21pbiddKGEsIGIpKSk7XG5cbiAgcmV0dXJuIHI7XG59XG5cbi8qKlxuICogcHZhbHVlIGNvcnJlY3Rpb24gZm9yIGZhbHNlIGRpc2NvdmVyeSByYXRlXG4gKlxuICogQGV4cG9ydFxuICogQHBhcmFtIHtGbG9hdDMyQXJyYXl9IHB2YWxzIFNldCBvZiBwLXZhbHVlcyBvZiB0aGUgaW5kaXZpZHVhbCB0ZXN0cy5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbYWxwaGE9MC4wNV0gRmFtaWx5LXdpc2UgZXJyb3IgcmF0ZS4gRGVmYXVsdHMgdG8gMC4wNS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWV0aG9kPSduJ10geydpJywgJ2luZGVwJywgJ3AnLCAncG9zY29ycicsICduJywgJ25lZ2NvcnInfSwgb3B0aW9uYWxcbiAqIFdoaWNoIG1ldGhvZCB0byB1c2UgZm9yIEZEUiBjb3JyZWN0aW9uLlxuICogYGB7J2knLCAnaW5kZXAnLCAncCcsICdwb3Njb3JyJ31gYCBhbGwgcmVmZXIgdG8gYGBmZHJfYmhgYFxuICogKEJlbmphbWluaS9Ib2NoYmVyZyBmb3IgaW5kZXBlbmRlbnQgb3IgcG9zaXRpdmVseVxuICogY29ycmVsYXRlZCB0ZXN0cykuIGBgeyduJywgJ25lZ2NvcnInfWBgIGJvdGggcmVmZXIgdG8gYGBmZHJfYnlgYFxuICogKEJlbmphbWluaS9ZZWt1dGllbGkgZm9yIGdlbmVyYWwgb3IgbmVnYXRpdmVseSBjb3JyZWxhdGVkIHRlc3RzKS5cbiAqIERlZmF1bHRzIHRvICduJy5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzU29ydGVkPWZhbHNlXSBJZiBGYWxzZSAoZGVmYXVsdCksIHRoZSBwX3ZhbHVlcyB3aWxsIGJlIHNvcnRlZCwgYnV0IHRoZSBjb3JyZWN0ZWRcbiAqIHB2YWx1ZXMgYXJlIGluIHRoZSBvcmlnaW5hbCBvcmRlci4gSWYgVHJ1ZSwgdGhlbiBpdCBhc3N1bWVkIHRoYXQgdGhlXG4gKiBwdmFsdWVzIGFyZSBhbHJlYWR5IHNvcnRlZCBpbiBhc2NlbmRpbmcgb3JkZXIuXG4gKiBAcmV0dXJuIHtbQXJyYXk8Ym9vbGVhbj4sIEZsb2F0MzJBcnJheV19IHJlamVjdGVkIDogbmRhcnJheSwgYm9vbFxuICogVHJ1ZSBpZiBhIGh5cG90aGVzaXMgaXMgcmVqZWN0ZWQsIEZhbHNlIGlmIG5vdFxuICogcHZhbHVlLWNvcnJlY3RlZCA6IG5kYXJyYXlcbiAqIHB2YWx1ZXMgYWRqdXN0ZWQgZm9yIG11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZyB0byBsaW1pdCBGRFJcbiAqIEBzZWVcbiAqIElmIHRoZXJlIGlzIHByaW9yIGluZm9ybWF0aW9uIG9uIHRoZSBmcmFjdGlvbiBvZiB0cnVlIGh5cG90aGVzaXMsIHRoZW4gYWxwaGFcbiAqIHNob3VsZCBiZSBzZXQgdG8gYGBhbHBoYSAqIG0vbV8wYGAgd2hlcmUgbSBpcyB0aGUgbnVtYmVyIG9mIHRlc3RzLFxuICogZ2l2ZW4gYnkgdGhlIHAtdmFsdWVzLCBhbmQgbV8wIGlzIGFuIGVzdGltYXRlIG9mIHRoZSB0cnVlIGh5cG90aGVzaXMuXG4gKiAoc2VlIEJlbmphbWluaSwgS3JpZWdlciBhbmQgWWVrdXRlbGkpXG4gKlxuICogVGhlIHR3by1zdGVwIG1ldGhvZCBvZiBCZW5qYW1pbmksIEtyaWVnZXIgYW5kIFlla3V0aWVsIHRoYXQgZXN0aW1hdGVzIHRoZSBudW1iZXJcbiAqIG9mIGZhbHNlIGh5cG90aGVzZXMgd2lsbCBiZSBhdmFpbGFibGUgKHNvb24pLlxuICpcbiAqIEJvdGggbWV0aG9kcyBleHBvc2VkIHZpYSB0aGlzIGZ1bmN0aW9uIChCZW5qYW1pbmkvSG9jaGJlcmcsIEJlbmphbWluaS9ZZWt1dGllbGkpXG4gKiBhcmUgYWxzbyBhdmFpbGFibGUgaW4gdGhlIGZ1bmN0aW9uIGBgbXVsdGlwbGV0ZXN0c2BgLCBhcyBgYG1ldGhvZD1cImZkcl9iaFwiYGAgYW5kXG4gKiBgYG1ldGhvZD1cImZkcl9ieVwiYGAsIHJlc3BlY3RpdmVseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZkcmNvcnJlY3Rpb24oXG4gIHB2YWxzOiBGbG9hdDMyQXJyYXksXG4gIGFscGhhOiBudW1iZXIgPSAwLjA1LFxuICBtZXRob2Q6IHN0cmluZyA9J24nLFxuICBpc1NvcnRlZDogYm9vbGVhbiA9IGZhbHNlKTogW0FycmF5PGJvb2xlYW4+LCBGbG9hdDMyQXJyYXldXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgYnJhY2Utc3R5bGVcbntcbiAgY29uc3Qgbkl0ZW1zID0gcHZhbHMubGVuZ3RoO1xuICBsZXQgcHZhbHNTb3J0ZWQ6IEZsb2F0MzJBcnJheTtcbiAgbGV0IHB2YWxzU29ydGluZDogSW50MzJBcnJheTtcbiAgbGV0IGNtID0gMDtcblxuICBpZiAoIWlzU29ydGVkKSB7XG4gICAgcHZhbHNTb3J0aW5kID0gX2FyZ3NvcnQocHZhbHMpO1xuICAgIHB2YWxzU29ydGVkID0gX3Rha2UocHZhbHNTb3J0aW5kLCBwdmFscyk7XG4gIH0gZWxzZSB7XG4gICAgcHZhbHNTb3J0aW5kID0gbmV3IEludDMyQXJyYXkobkl0ZW1zKS5maWxsKDApLm1hcCgoXywgaSkgPT4gKGkpKTtcbiAgICBwdmFsc1NvcnRlZCA9IHB2YWxzOyAvLyBhbGlhc1xuICB9XG5cbiAgbGV0IGVjZGZmYWN0b3IgPSBfZWNkZihwdmFsc1NvcnRlZCk7XG5cbiAgaWYgKFsnbicsICduZWdjb3JyJ10uaW5jbHVkZXMobWV0aG9kKSkge1xuICAgIGNtID0gX2NtKG5JdGVtcyk7XG4gICAgZWNkZmZhY3RvciA9IF9mYWN0b3IoZWNkZmZhY3RvciwgY20sICcvJyk7XG4gIH0gZWxzZSBpZiAoIVsnaScsICdpbmRlcCcsICdwJywgJ3Bvc2NvcnInXS5pbmNsdWRlcyhtZXRob2QpKVxuICAgIHRocm93IG5ldyBFcnJvcignb25seSBpbmRlcCBhbmQgbmVnY29yciBpbXBsZW1lbnRlZCcpO1xuXG4gIGNvbnN0IHJlamVjdDogYm9vbGVhbltdID0gbmV3IEFycmF5KG5JdGVtcykuZmlsbChmYWxzZSk7XG4gIGxldCByZWplY3RtYXggPSAtMTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IG5JdGVtczsgKytpKSB7XG4gICAgaWYgKHB2YWxzU29ydGVkW2ldIDw9IGVjZGZmYWN0b3JbaV0qYWxwaGEpXG4gICAgICByZWplY3RtYXggPSBpO1xuICB9XG5cbiAgaWYgKHJlamVjdG1heCA+PSAwKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZWplY3RtYXg7ICsraSlcbiAgICAgIHJlamVjdFtpXSA9IHRydWU7XG4gIH1cblxuICBsZXQgcHZhbHNDb3JyZWN0ZWQgPSBfdmZhY3RvcihwdmFsc1NvcnRlZCwgZWNkZmZhY3RvciwgJy8nKTtcbiAgcHZhbHNDb3JyZWN0ZWQgPSBfbWluaW11bUFjY3VtdWxhdGUocHZhbHNDb3JyZWN0ZWQucmV2ZXJzZSgpKS5yZXZlcnNlKCk7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuSXRlbXM7ICsraSkge1xuICAgIGlmIChwdmFsc0NvcnJlY3RlZFtpXSA+IDEpXG4gICAgICBwdmFsc0NvcnJlY3RlZFtpXSA9IDE7XG4gIH1cblxuICBpZiAoIWlzU29ydGVkKSB7XG4gICAgY29uc3QgcHZhbHNDb3JyZWN0ZWRfID0gX2dpdmUocHZhbHNDb3JyZWN0ZWQsIHB2YWxzU29ydGluZCk7XG4gICAgY29uc3QgcmVqZWN0XyA9IF9naXZlYihyZWplY3QsIHB2YWxzU29ydGluZCk7XG4gICAgcmV0dXJuIFtyZWplY3RfLCBwdmFsc0NvcnJlY3RlZF9dO1xuICB9XG4gIHJldHVybiBbcmVqZWN0LCBwdmFsc0NvcnJlY3RlZF07XG59XG4iXX0=","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\nimport {tTest} from '@datagrok-libraries/statistics/src/tests';\nimport {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests';\nimport {SEMTYPE, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\nimport {getGroups} from './experiment-setup';\n\n/** Guard for menu/dialog handlers that need DE results. Returns true if DE has been\n * run on `df`; otherwise warns the user via `grok.shell.warning` and returns false.\n * Each caller passes its own warning text so existing user-visible copy is preserved.\n * Use as: `if (!requireDifferentialExpression(df, '...')) return;` */\nexport function requireDifferentialExpression(df: DG.DataFrame, message: string): boolean {\n if (df.getTag('proteomics.de_complete') === 'true')\n return true;\n grok.shell.warning(message);\n return false;\n}\n\n/** Extract non-null float values across named columns for a single row. */\nfunction getGroupValues(df: DG.DataFrame, colNames: string[], rowIdx: number): number[] {\n const values: number[] = [];\n for (const name of colNames) {\n const col = df.columns.byName(name);\n if (col && !col.isNone(rowIdx))\n values.push(col.get(rowIdx));\n }\n return values;\n}\n\n/** Compute arithmetic mean of a number array. */\nfunction mean(vals: number[]): number {\n let sum = 0;\n for (let i = 0; i < vals.length; i++)\n sum += vals[i];\n return sum / vals.length;\n}\n\n/** Run client-side Welch's t-test differential expression with BH FDR correction.\n * Compares group2 (treatment) vs group1 (control). Adds log2FC, p-value, adj.p-value,\n * and significant columns to the DataFrame in-place. */\nexport function runDifferentialExpression(\n df: DG.DataFrame,\n group1Cols: string[],\n group2Cols: string[],\n group1Name: string,\n group2Name: string,\n fcThreshold: number = DEFAULT_FC_THRESHOLD,\n pThreshold: number = DEFAULT_P_THRESHOLD,\n): {tested: number; untestable: number} {\n // Compute per-row stats into typed arrays first, then bulk-init the columns.\n // Cheaper than column.set() per row, which hops the JS/native bridge each cell.\n const nRows = df.rowCount;\n const fcArr = new Float32Array(nRows);\n const pArr = new Float32Array(nRows);\n const adjArr = new Float32Array(nRows);\n fcArr.fill(DG.FLOAT_NULL);\n pArr.fill(DG.FLOAT_NULL);\n adjArr.fill(DG.FLOAT_NULL);\n\n const testableIndices: number[] = [];\n const rawPValues: number[] = [];\n\n for (let i = 0; i < nRows; i++) {\n const vals1 = getGroupValues(df, group1Cols, i);\n const vals2 = getGroupValues(df, group2Cols, i);\n if (vals1.length < 2 || vals2.length < 2) continue;\n\n fcArr[i] = mean(vals2) - mean(vals1);\n const pVal = tTest(vals1, vals2)['p-value'];\n pArr[i] = pVal;\n testableIndices.push(i);\n rawPValues.push(pVal);\n }\n\n // BH FDR correction on testable proteins only\n if (rawPValues.length > 0) {\n // alpha is passed for intent/consistency with the user's cutoff; it only\n // affects the (discarded) reject array — BH-adjusted p-values are\n // alpha-independent, so this does not change `corrected`.\n const [, corrected] = fdrcorrection(new Float32Array(rawPValues), pThreshold, 'i');\n for (let j = 0; j < testableIndices.length; j++)\n adjArr[testableIndices[j]] = corrected[j];\n }\n\n const log2fcCol = df.columns.addNewFloat('log2FC');\n const pValCol = df.columns.addNewFloat('p-value');\n const adjPValCol = df.columns.addNewFloat('adj.p-value');\n log2fcCol.init((i) => fcArr[i]);\n pValCol.init((i) => pArr[i]);\n adjPValCol.init((i) => adjArr[i]);\n\n const sigCol = df.columns.addNewBool('significant');\n sigCol.init((i) => {\n const adjP = adjArr[i];\n const fc = fcArr[i];\n if (adjP === DG.FLOAT_NULL || fc === DG.FLOAT_NULL) return false;\n return Math.abs(fc) >= fcThreshold && adjP <= pThreshold;\n });\n\n // Assign semantic types\n log2fcCol.semType = SEMTYPE.LOG2FC;\n pValCol.semType = SEMTYPE.P_VALUE;\n adjPValCol.semType = SEMTYPE.P_VALUE;\n\n // Mark DE as complete\n df.setTag('proteomics.de_complete', 'true');\n df.fireValuesChanged();\n\n const tested = testableIndices.length;\n const untestable = df.rowCount - tested;\n return {tested, untestable};\n}\n\n/** Build a clean expression dataframe with simple column names (s1, s2, ...)\n * to avoid encoding issues with special characters in column names.\n * Bulk-copies via getRawData/fromFloat32Array — per-row set() crosses the JS/native\n * bridge once per cell and stalls the main thread on real-size frames (see\n * feedback_dg_column_bulk_init memory note). */\nfunction buildExpressionDf(\n df: DG.DataFrame, group1Cols: string[], group2Cols: string[],\n): DG.DataFrame {\n const allCols = [...group1Cols, ...group2Cols];\n const cols: DG.Column[] = [];\n for (let i = 0; i < allCols.length; i++) {\n const src = df.columns.byName(allCols[i]);\n // getRawData returns the underlying Float32/Float64Array; nulls are already\n // encoded as DG.FLOAT_NULL, so a straight copy preserves missingness.\n const raw = src.getRawData();\n const buf = new Float32Array(raw.length);\n buf.set(raw);\n cols.push(DG.Column.fromFloat32Array(`s${i + 1}`, buf));\n }\n return DG.DataFrame.fromColumns(cols);\n}\n\n/** Copy log2FC / p.value / adj.p.value / significant columns from an R-script\n * result frame into `df` as new columns, returning the count of TRUE\n * significant rows.\n *\n * Alignment is by the result's `row` column (1-based input index emitted by\n * the R scripts), NOT by row position. This is load-bearing: DEqMS's\n * `outputResult()` returns rows sorted by significance, so a positional copy\n * silently assigns every protein another protein's statistics. When `row` is\n * absent (defensive fallback for any R output that doesn't emit it) the copy\n * degrades to positional.\n *\n * R serialization sometimes flattens booleans to 0/1 or \"TRUE\"/\"FALSE\"\n * strings — the truthiness check covers all three forms. */\nexport function copyDEResultsToFrame(df: DG.DataFrame, result: DG.DataFrame): number {\n const nRows = df.rowCount;\n const m = result.rowCount;\n\n const fcRaw = result.columns.byName('log2FC').getRawData() as Float32Array | Float64Array;\n const pRaw = result.columns.byName('p.value').getRawData() as Float32Array | Float64Array;\n const aRaw = result.columns.byName('adj.p.value').getRawData() as Float32Array | Float64Array;\n const rSig = result.columns.byName('significant');\n\n // result row j -> df row index. With the `row` key, realign by input index\n // (1-based); without it, identity (positional) as a defensive fallback.\n const rowCol = result.col('row');\n const target = new Int32Array(m);\n if (rowCol) {\n const rowRaw = rowCol.getRawData();\n for (let j = 0; j < m; j++) target[j] = (rowRaw[j] | 0) - 1;\n } else {\n for (let j = 0; j < m; j++) target[j] = j;\n }\n\n // Pre-fill with FLOAT_NULL so any df row the result doesn't cover stays null\n // rather than a spurious 0 (positional copy used to assume full coverage).\n const log2fcBuf = new Float32Array(nRows); log2fcBuf.fill(DG.FLOAT_NULL);\n const pBuf = new Float32Array(nRows); pBuf.fill(DG.FLOAT_NULL);\n const aBuf = new Float32Array(nRows); aBuf.fill(DG.FLOAT_NULL);\n const sigArr = new Uint8Array(nRows);\n let sigCount = 0;\n\n for (let j = 0; j < m; j++) {\n const t = target[j];\n if (t < 0 || t >= nRows) continue;\n log2fcBuf[t] = fcRaw[j];\n pBuf[t] = pRaw[j];\n aBuf[t] = aRaw[j];\n const v = rSig.get(j);\n if (v === true || v === 1 || v === '1' || v === 'TRUE') {\n sigArr[t] = 1;\n sigCount++;\n }\n }\n\n const log2fcCol = DG.Column.fromFloat32Array('log2FC', log2fcBuf);\n const pValCol = DG.Column.fromFloat32Array('p-value', pBuf);\n const adjPValCol = DG.Column.fromFloat32Array('adj.p-value', aBuf);\n const sigCol = df.columns.addNewBool('significant');\n sigCol.init((i) => sigArr[i] === 1);\n\n log2fcCol.semType = SEMTYPE.LOG2FC;\n pValCol.semType = SEMTYPE.P_VALUE;\n adjPValCol.semType = SEMTYPE.P_VALUE;\n\n df.columns.add(log2fcCol);\n df.columns.add(pValCol);\n df.columns.add(adjPValCol);\n\n return sigCount;\n}\n\n/** Run limma moderated t-test via server-side R script.\n * Returns the number of significant proteins found. */\nasync function runLimmaDE(\n df: DG.DataFrame,\n group1Cols: string[],\n group2Cols: string[],\n fcThreshold: number,\n pThreshold: number,\n): Promise<number> {\n const exprDf = buildExpressionDf(df, group1Cols, group2Cols);\n\n const result: DG.DataFrame = await grok.functions.call('Proteomics:LimmaDE', {\n exprDf: exprDf,\n nGroup1: group1Cols.length,\n fcThreshold: fcThreshold,\n pThreshold: pThreshold,\n });\n\n const sigCount = copyDEResultsToFrame(df, result);\n\n df.setTag('proteomics.de_complete', 'true');\n df.fireValuesChanged();\n\n return sigCount;\n}\n\n/** Run DEqMS peptide-count-weighted differential expression via server-side R script.\n * Returns the number of significant proteins found. */\nasync function runDeqmsDE(\n df: DG.DataFrame,\n group1Cols: string[],\n group2Cols: string[],\n peptideCountCol: DG.Column,\n fcThreshold: number,\n pThreshold: number,\n): Promise<number> {\n const exprDf = buildExpressionDf(df, group1Cols, group2Cols);\n\n // Build single-column peptide count DataFrame\n const peptideDf = DG.DataFrame.create(df.rowCount);\n const countCol = peptideDf.columns.addNewInt('count');\n for (let r = 0; r < df.rowCount; r++)\n countCol.set(r, peptideCountCol.isNone(r) ? 1 : Math.round(peptideCountCol.get(r) as number));\n\n const result: DG.DataFrame = await grok.functions.call('Proteomics:DeqmsDE', {\n exprDf: exprDf,\n nGroup1: group1Cols.length,\n peptideDf: peptideDf,\n fcThreshold: fcThreshold,\n pThreshold: pThreshold,\n });\n\n const sigCount = copyDEResultsToFrame(df, result);\n\n df.setTag('proteomics.de_complete', 'true');\n df.setTag('proteomics.de_method', 'deqms');\n df.fireValuesChanged();\n\n return sigCount;\n}\n\n/**\n * R3/D-09: the DE dialog's default Comparison. Returns the declared/intended\n * contrast `${g1} vs ${g2}` — group1 is the parser's first condition, which is\n * Spectronaut's declared Numerator (13-WAVE0-FINDINGS.md A3). The OK-handler's\n * `value === pairs[1]` index logic maps this string to numerator = group1.\n * Previously the default was the alphabetical `pairs[0]` (`${g2} vs ${g1}`),\n * the reverse of the declared contrast — the documented mirror defect\n * (memory project_proteomics_spectronaut_de_direction_default). The dropdown\n * still offers both orientations; only this default changed (direction-only).\n */\nexport function getDefaultComparison(g1Name: string, g2Name: string): string {\n return `${g1Name} vs ${g2Name}`;\n}\n\n/** Show differential expression dialog with prerequisite checks.\n * @param onComplete Optional callback invoked after DE completes successfully. */\nexport function showDEDialog(df: DG.DataFrame, onComplete?: () => void): void {\n const groups = getGroups(df);\n if (!groups) {\n grok.shell.warning('Please annotate experimental groups first (Proteomics | Annotate Experiment)');\n return;\n }\n\n if (df.getTag('proteomics.de_complete') === 'true') {\n grok.shell.warning('Differential expression already performed');\n return;\n }\n\n const g1 = groups.group1;\n const g2 = groups.group2;\n\n const infoText = ui.divText(\n `Group 1: ${g1.name} (${g1.columns.length} samples), ` +\n `Group 2: ${g2.name} (${g2.columns.length} samples)`,\n );\n\n // Comparison direction picker\n const pairs = [`${g2.name} vs ${g1.name}`, `${g1.name} vs ${g2.name}`];\n const comparisonInput = ui.input.choice('Comparison', {\n value: getDefaultComparison(g1.name, g2.name), // D-09: declared contrast, not pairs[0]\n items: pairs,\n nullable: false,\n });\n\n // Dynamic hint text for FC interpretation. Derive direction from pairs index\n // (not string-splitting) so group names containing \" vs \" stay intact.\n const hintDiv = ui.div();\n hintDiv.style.cssText = 'font-style:italic; color:#888; font-size:12px; margin-bottom:8px;';\n const updateHint = () => {\n const isReversed = comparisonInput.value === pairs[1];\n const numerator = isReversed ? g1.name : g2.name;\n const denominator = isReversed ? g2.name : g1.name;\n hintDiv.textContent = `Positive log2FC = higher in ${numerator}, Negative log2FC = higher in ${denominator}`;\n };\n comparisonInput.onChanged.subscribe(updateHint);\n updateHint();\n\n const methodInput = ui.input.choice('Method', {\n value: 'limma',\n items: ['limma', 'DEqMS', 't-test'],\n nullable: false,\n });\n methodInput.setTooltip('limma: moderated t-test; DEqMS: peptide-count-weighted variance; t-test: client-side Welch\\'s t-test');\n\n // Find default peptide count column\n const defaultPeptideCol = df.columns.toList().find((c) =>\n c.name === 'Unique peptides' || c.name === 'Peptides',\n ) ?? undefined;\n\n const peptideColInput = ui.input.column('Peptide count column', {\n table: df,\n value: defaultPeptideCol,\n filter: (col: DG.Column) => col.type === DG.COLUMN_TYPE.INT || col.type === DG.COLUMN_TYPE.FLOAT,\n nullable: false,\n });\n peptideColInput.setTooltip('Column with peptide/spectra counts per protein');\n\n // Show/hide peptide count picker based on method selection\n const peptideRow = peptideColInput.root;\n peptideRow.style.display = 'none';\n methodInput.onChanged.subscribe(() => {\n peptideRow.style.display = methodInput.value === 'DEqMS' ? '' : 'none';\n });\n\n const fcInput = ui.input.float('|log2FC| threshold', {value: DEFAULT_FC_THRESHOLD});\n fcInput.setTooltip('Minimum absolute fold change for significance');\n\n const pInput = ui.input.float('Adj. p-value threshold', {value: DEFAULT_P_THRESHOLD});\n pInput.setTooltip('Maximum adjusted p-value for significance');\n\n ui.dialog('Differential Expression')\n .add(infoText)\n .add(comparisonInput)\n .add(hintDiv)\n .add(methodInput)\n .add(peptideColInput)\n .add(fcInput)\n .add(pInput)\n .onOK(async () => {\n const fc = fcInput.value ?? DEFAULT_FC_THRESHOLD;\n const p = pInput.value ?? DEFAULT_P_THRESHOLD;\n const method = methodInput.value;\n\n // Determine numerator/denominator from pairs index, not string-splitting,\n // so group names containing \" vs \" don't break the comparison.\n const reversed = comparisonInput.value === pairs[1];\n const numeratorCols = reversed ? g1.columns : g2.columns;\n const denominatorCols = reversed ? g2.columns : g1.columns;\n const numeratorName = reversed ? g1.name : g2.name;\n const denominatorName = reversed ? g2.name : g1.name;\n\n const pi = DG.TaskBarProgressIndicator.create(`Running ${method} analysis...`);\n\n try {\n if (method === 't-test') {\n const result = runDifferentialExpression(\n df, denominatorCols, numeratorCols, denominatorName, numeratorName, fc, p,\n );\n df.setTag('proteomics.de_method', 't-test');\n grok.shell.info(\n `DE complete (t-test): ${result.tested} proteins tested, ${result.untestable} untestable`,\n );\n } else if (method === 'DEqMS') {\n const pepCol = peptideColInput.value;\n if (!pepCol) {\n grok.shell.error('Please select a peptide count column for DEqMS');\n return;\n }\n try {\n const sigCount = await runDeqmsDE(df, denominatorCols, numeratorCols, pepCol, fc, p);\n df.setTag('proteomics.de_method', 'deqms');\n grok.shell.info(`DE complete (DEqMS): ${sigCount} significant proteins`);\n } catch (deqmsErr: any) {\n console.warn('DEqMS failed, trying limma:', deqmsErr);\n pi.update(50, 'DEqMS unavailable, trying limma...');\n grok.shell.warning('DEqMS unavailable, trying limma...');\n try {\n const sigCount = await runLimmaDE(df, denominatorCols, numeratorCols, fc, p);\n df.setTag('proteomics.de_method', 'limma');\n grok.shell.info(`DE complete (limma fallback): ${sigCount} significant proteins`);\n } catch (limmaErr: any) {\n console.warn('Limma DE also failed, using client-side fallback:', limmaErr);\n pi.update(75, 'Server-side DE unavailable, using client-side t-test...');\n grok.shell.warning('R environment unavailable — using client-side t-test');\n const result = runDifferentialExpression(\n df, denominatorCols, numeratorCols, denominatorName, numeratorName, fc, p,\n );\n df.setTag('proteomics.de_method', 't-test');\n grok.shell.info(\n `DE complete (t-test): ${result.tested} proteins tested, ` +\n `${result.untestable} untestable`,\n );\n }\n }\n } else {\n try {\n const sigCount = await runLimmaDE(df, denominatorCols, numeratorCols, fc, p);\n df.setTag('proteomics.de_method', 'limma');\n grok.shell.info(`DE complete (limma): ${sigCount} significant proteins`);\n } catch (e: any) {\n pi.update(50, 'Limma unavailable, using client-side t-test...');\n grok.shell.warning('R environment unavailable — using client-side t-test');\n console.warn('Limma DE failed, using client-side fallback:', e);\n const result = runDifferentialExpression(\n df, denominatorCols, numeratorCols, denominatorName, numeratorName, fc, p,\n );\n df.setTag('proteomics.de_method', 't-test');\n grok.shell.info(\n `DE complete (t-test): ${result.tested} proteins tested, ` +\n `${result.untestable} untestable`,\n );\n }\n }\n } finally {\n pi.close();\n }\n\n if (onComplete)\n onComplete();\n })\n .show();\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {findProteomicsColumns} from '../utils/column-detection';\nimport {DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\nimport {splitGenesByDirection, countSignificantProteins} from './enrichment';\n\n/**\n * Exports the exact inputs an enrichment run would use — the up-regulated gene\n * list, the down-regulated gene list, and the background (every detected gene) —\n * so the analyst can reproduce or hand off the g:Profiler query outside Datagrok\n * (CK-omics CKomics_tool2.py:4531-4640 wrote the same three lists).\n *\n * Deliberately network-free: it reads the resolved gene-name column (falling\n * back to protein IDs) rather than re-running g:Convert, mirroring the pipeline's\n * non-mapping path via the SAME `splitGenesByDirection` so the exported lists\n * match what Enrichment Analysis would query at identical thresholds.\n */\n\n/** Tidy long-format CSV: `gene,list` with list ∈ {up, down, background}. Each\n * list is filter-and-copy friendly for g:Profiler; a gene appears under\n * `background` and (if significant) also under `up`/`down` — faithful to\n * g:Profiler semantics where the background is the full universe. */\nexport function buildEnrichmentInputsCsv(\n df: DG.DataFrame, fcThreshold: number, pThreshold: number,\n): {csv: string; counts: {up: number; down: number; background: number}} {\n const cols = findProteomicsColumns(df);\n if (!cols.log2fc || !cols.pValue)\n throw new Error('No log2FC or adjusted p-value columns found. Run Differential Expression first.');\n\n // Prefer resolved gene symbols; fall back to protein IDs so the export still\n // works before gene mapping (honest — the header says what was used).\n const idCol = cols.geneName ?? cols.proteinId;\n if (!idCol)\n throw new Error('No gene-name or protein-ID column found to export.');\n\n const geneForRow = new Map<number, string>();\n for (let i = 0; i < df.rowCount; i++) {\n const v = idCol.get(i) as string | null;\n if (v) geneForRow.set(i, String(v));\n }\n\n const fcRaw = cols.log2fc.getRawData() as Float32Array | Float64Array;\n const pRaw = cols.pValue.getRawData() as Float32Array | Float64Array;\n const {upGenes, downGenes, background} =\n splitGenesByDirection(geneForRow, fcRaw, pRaw, fcThreshold, pThreshold);\n\n const esc = (s: string): string =>\n /[\",\\n]/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n const rows: string[] = ['gene,list'];\n for (const g of upGenes) rows.push(`${esc(g)},up`);\n for (const g of downGenes) rows.push(`${esc(g)},down`);\n for (const g of background) rows.push(`${esc(g)},background`);\n\n return {\n csv: rows.join('\\n'),\n counts: {up: upGenes.length, down: downGenes.length, background: background.length},\n };\n}\n\n/** Small dialog to pick significance thresholds (seeded from the package\n * defaults, matching the Enrichment dialog) and download the input lists as one\n * CSV. Immediate download on OK via `DG.Utils.download`. */\nexport function showEnrichmentInputExportDialog(df: DG.DataFrame): void {\n const cols = findProteomicsColumns(df);\n if (!cols.log2fc || !cols.pValue) {\n grok.shell.warning('No log2FC or p-value columns found. Run Differential Expression first.');\n return;\n }\n\n const fcInput = ui.input.float('|log2FC| threshold', {value: DEFAULT_FC_THRESHOLD});\n fcInput.setTooltip('Minimum absolute fold change for a gene to count as up/down.');\n const pInput = ui.input.float('Adj. p-value threshold', {value: DEFAULT_P_THRESHOLD});\n pInput.setTooltip('Maximum adjusted p-value for a gene to count as up/down.');\n\n const countDiv = ui.divText('');\n const updateCount = () => {\n const r = countSignificantProteins(df, fcInput.value ?? DEFAULT_FC_THRESHOLD,\n pInput.value ?? DEFAULT_P_THRESHOLD, cols.log2fc!, cols.pValue!);\n countDiv.textContent = `${r.significant} of ${r.total.toLocaleString()} proteins significant`;\n };\n updateCount();\n fcInput.onChanged.subscribe(updateCount);\n pInput.onChanged.subscribe(updateCount);\n\n ui.dialog('Export Enrichment Inputs')\n .add(countDiv)\n .add(fcInput)\n .add(pInput)\n .onOK(() => {\n const fc = fcInput.value ?? DEFAULT_FC_THRESHOLD;\n const p = pInput.value ?? DEFAULT_P_THRESHOLD;\n const {csv, counts} = buildEnrichmentInputsCsv(df, fc, p);\n const base = df.name ? `${df.name} — enrichment inputs` : 'enrichment inputs';\n DG.Utils.download(`${base}.csv`, csv, 'text/csv');\n grok.shell.info(\n `Exported ${counts.up} up, ${counts.down} down, ${counts.background} background genes.`);\n })\n .show();\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\nimport {parseAccession} from '../panels/uniprot-panel';\nimport {findProteomicsColumns} from '../utils/column-detection';\nimport {SEMTYPE, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\nimport {openEnrichmentVisualization} from '../viewers/enrichment-viewers';\nimport {requireDifferentialExpression} from './differential-expression';\nimport {getOrganism, setOrganism} from './experiment-setup';\nimport {ORGANISM_LIST, detectOrganismCode, organismDisplayForCode} from '../utils/organisms';\n\n// ORGANISM_LIST now lives in utils/organisms (single source); re-exported here so\n// existing importers (and the enrichment tests) keep resolving it from this module.\nexport {ORGANISM_LIST};\n\n// --- Constants ---\n\nconst GPROFILER_BASE = 'https://biit.cs.ut.ee/gprofiler';\n\n// --- Types ---\n\nexport interface ConvertResult {\n incoming: string;\n converted: string;\n name: string;\n description: string;\n namespaces: string;\n n_incoming: number;\n n_converted: number;\n}\n\nexport interface GostResult {\n native: string;\n name: string;\n source: string;\n p_value: number;\n significant: boolean;\n term_size: number;\n query_size: number;\n intersection_size: number;\n effective_domain_size: number;\n precision: number;\n recall: number;\n intersections: string[][];\n}\n\n// --- API Client ---\n\nasync function fetchWithTimeout(\n url: string, options: RequestInit, timeoutMs: number = 30000,\n): Promise<Response> {\n // External URLs go through grok.dapi.fetchProxy to avoid browser CORS.\n // Datagrok's proxy does not currently honor AbortSignal, so we race the\n // request against a timeout promise to enforce the bound.\n const proxied = grok.dapi.fetchProxy(url, options);\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('g:Profiler API request timed out. The service may be temporarily unavailable.')), timeoutMs),\n );\n const resp = await Promise.race([proxied, timeout]);\n if (!resp.ok)\n throw new Error(`g:Profiler API returned status ${resp.status}`);\n return resp;\n}\n\nexport async function gConvert(\n accessions: string[],\n organism: string = 'hsapiens',\n): Promise<ConvertResult[]> {\n const resp = await fetchWithTimeout(`${GPROFILER_BASE}/api/convert/convert/`, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify({\n organism: organism,\n query: accessions,\n target: 'ENSG',\n numeric_ns: '',\n output: 'json',\n }),\n });\n const data = await resp.json();\n return data.result ?? [];\n}\n\nexport async function gGOSt(\n queryGenes: string[],\n backgroundGenes: string[],\n organism: string,\n sources: string[],\n threshold: number = DEFAULT_P_THRESHOLD,\n): Promise<GostResult[]> {\n const resp = await fetchWithTimeout(`${GPROFILER_BASE}/api/gost/profile/`, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify({\n organism: organism,\n query: queryGenes,\n sources: sources,\n user_threshold: threshold,\n significance_threshold_method: 'fdr',\n domain_scope: 'custom',\n background: backgroundGenes,\n all_results: true,\n ordered: false,\n no_evidences: false,\n combined: false,\n measure_underrepresentation: false,\n no_iea: false,\n numeric_ns: '',\n output: 'json',\n }),\n });\n const data = await resp.json();\n // g:GOSt nests results: data.result is an array of per-query result objects,\n // each containing a `.result` array of term results.\n if (!data.result)\n return [];\n // Handle array of query results (standard structure)\n if (Array.isArray(data.result) && data.result.length > 0 && data.result[0]?.result)\n return data.result[0].result as GostResult[];\n // Fallback: if data.result is directly the results array\n if (Array.isArray(data.result))\n return data.result as GostResult[];\n return [];\n}\n\n// --- Smart Pathway Filter (R5/D-13/D-14) ---\n\n// LOCKED CLIENT CONTRACT — port verbatim from\n// ~/Downloads/ck/CKomics_tool2.py:4685-4736 (apply_smart_pathway_filtering).\n// Do not re-derive heuristics; any change requires a CONTEXT update.\n\nexport const GENERIC_PARENT_TERMS = [\n 'localization', 'cellular component organization', 'transport',\n 'cellular process', 'biological process', 'metabolic process',\n] as const;\n\nexport const SPECIFIC_CHILD_TERMS = ['actin', 'vesicle', 'endocytosis', 'cytoskeleton'] as const;\n\nexport interface SmartFilterStats {\n total: number;\n kept: number;\n droppedParents: number;\n cappedAtN: number;\n}\n\n/** Verbatim port of CK-omics apply_smart_pathway_filtering (lines 4685-4736).\n *\n * Algorithm:\n * 1. Partition into GO:BP rows and `other_data` (everything else).\n * 2. Sort GO:BP by p_value ASCENDING.\n * 3. Walk GO:BP in sorted order: drop a row when its name contains any\n * GENERIC_PARENT term AND the already-kept list already contains a\n * SPECIFIC_CHILD-term row. Otherwise keep it. Stop at `maxPerSource`.\n * 4. Non-GO:BP rows are sorted by p_value ASC and `.head(maxPerSource)` —\n * a COMBINED cap across all non-GO:BP sources, not per-source\n * (Assumption A4; CK-omics line 4731 explicitly uses combined .head). */\nexport function applySmartPathwayFilter(\n results: GostResult[], maxPerSource = 15,\n): {kept: GostResult[]; stats: SmartFilterStats} {\n if (results.length === 0) {\n return {kept: [], stats: {total: 0, kept: 0, droppedParents: 0, cappedAtN: maxPerSource}};\n }\n\n const goBp = results.filter((r) => r.source === 'GO:BP');\n const other = results.filter((r) => r.source !== 'GO:BP');\n\n let droppedParents = 0;\n const filteredGoBp: GostResult[] = [];\n if (goBp.length > 0) {\n const sorted = [...goBp].sort((a, b) => a.p_value - b.p_value);\n for (const r of sorted) {\n const name = (r.name ?? '').toLowerCase();\n const isGeneric = GENERIC_PARENT_TERMS.some((g) => name.includes(g));\n if (isGeneric) {\n const hasSpecificChild = filteredGoBp.some((existing) =>\n SPECIFIC_CHILD_TERMS.some((s) => (existing.name ?? '').toLowerCase().includes(s)));\n if (hasSpecificChild) { droppedParents++; continue; }\n }\n filteredGoBp.push(r);\n if (filteredGoBp.length >= maxPerSource) break;\n }\n }\n\n const otherSorted = [...other].sort((a, b) => a.p_value - b.p_value);\n const otherCapped = otherSorted.slice(0, maxPerSource);\n\n const kept = [...filteredGoBp, ...otherCapped].sort((a, b) => a.p_value - b.p_value);\n return {\n kept,\n stats: {\n total: results.length,\n kept: kept.length,\n droppedParents,\n cappedAtN: maxPerSource,\n },\n };\n}\n\n// --- Result Builder ---\n\nexport function buildEnrichmentDf(\n results: GostResult[],\n queryGenes: string[],\n pThreshold: number = DEFAULT_P_THRESHOLD,\n direction?: 'Up' | 'Down',\n): DG.DataFrame {\n const n = results.length;\n const df = DG.DataFrame.create(n);\n df.name = 'Enrichment Results';\n\n // Pre-derive the comma-joined member-gene string per row so the column init\n // doesn't repeat the intersections-array walk per cell.\n const memberGeneStrs = results.map((r) => {\n if (!r.intersections) return '';\n const members: string[] = [];\n const lim = Math.min(queryGenes.length, r.intersections.length);\n for (let j = 0; j < lim; j++) {\n if (r.intersections[j] && r.intersections[j].length > 0)\n members.push(queryGenes[j]);\n }\n return members.join(', ');\n });\n\n const sourceCol = df.columns.addNewString('Source');\n const termIdCol = df.columns.addNewString('Term ID');\n const termNameCol = df.columns.addNewString('Term Name');\n // g:GOSt with significance_threshold_method='fdr' returns the FDR-corrected\n // p-value (and no separate raw p-value) — we expose it under the FDR column\n // to keep semantics honest. Downstream consumers should read FDR.\n const fdrCol = df.columns.addNewFloat('FDR');\n const geneCountCol = df.columns.addNewInt('Gene Count');\n const geneRatioCol = df.columns.addNewFloat('Gene Ratio');\n const intersectionCol = df.columns.addNewString('Intersection');\n\n sourceCol.init((i) => results[i].source);\n termIdCol.init((i) => results[i].native);\n termNameCol.init((i) => results[i].name);\n fdrCol.init((i) => results[i].p_value);\n geneCountCol.init((i) => results[i].intersection_size);\n geneRatioCol.init((i) => results[i].precision);\n intersectionCol.init((i) => memberGeneStrs[i]);\n\n const fdrRaw = fdrCol.getRawData() as Float32Array | Float64Array;\n const sigCol = df.columns.addNewBool('Significant');\n sigCol.init((i) => fdrRaw[i] !== DG.FLOAT_NULL && fdrRaw[i] <= pThreshold);\n\n // Optional directional label (R2 up/down split). Categorical, bulk-init\n // (memory feedback_dg_column_bulk_init — never per-row set).\n if (direction) {\n const directionCol = df.columns.addNewString('Direction');\n directionCol.init(() => direction);\n }\n\n // Color coding on FDR column\n fdrCol.setTag('color-coding-type', 'Linear');\n fdrCol.setTag('color-coding-linear', '{\"0\":\"#2ecc71\",\"0.05\":\"#f39c12\",\"1\":\"#e74c3c\"}');\n\n df.setTag('proteomics.enrichment', 'true');\n return df;\n}\n\n/**\n * Splits the detected genes into up/down significant query sets and the shared\n * all-detected background. Ported from CK-omics run_gprofiler_analysis: strict\n * `fc > 0` / `fc < 0`; background is every detected gene (used by BOTH\n * directional g:Profiler calls). Null fc/p rows count toward background only.\n */\nexport function splitGenesByDirection(\n geneForRow: Map<number, string>,\n fcRaw: Float32Array | Float64Array,\n pRaw: Float32Array | Float64Array,\n fcThreshold: number,\n pThreshold: number,\n): {upGenes: string[]; downGenes: string[]; background: string[]} {\n const up: Set<string> = new Set();\n const down: Set<string> = new Set();\n const background: Set<string> = new Set();\n for (const [row, gene] of geneForRow) {\n background.add(gene);\n const fc = fcRaw[row];\n const adjP = pRaw[row];\n if (fc !== DG.FLOAT_NULL && adjP !== DG.FLOAT_NULL &&\n adjP <= pThreshold && Math.abs(fc) >= fcThreshold) {\n if (fc > 0) up.add(gene);\n else if (fc < 0) down.add(gene);\n }\n }\n return {upGenes: [...up], downGenes: [...down], background: [...background]};\n}\n\n// --- Significant Protein Counter ---\n\nexport function countSignificantProteins(\n df: DG.DataFrame,\n fcThreshold: number,\n pThreshold: number,\n log2fcCol: DG.Column,\n pValCol: DG.Column,\n): {significant: number; total: number} {\n // Bulk-read via getRawData so we don't pay a 3× JS/native bridge hop per row.\n const n = df.rowCount;\n const fcRaw = log2fcCol.getRawData() as Float32Array | Float64Array;\n const pRaw = pValCol.getRawData() as Float32Array | Float64Array;\n let significant = 0;\n for (let i = 0; i < n; i++) {\n const fc = fcRaw[i];\n const p = pRaw[i];\n if (fc === DG.FLOAT_NULL || p === DG.FLOAT_NULL) continue;\n if (Math.abs(fc) >= fcThreshold && p <= pThreshold)\n significant++;\n }\n return {significant, total: n};\n}\n\n// --- Pipeline Orchestrator ---\n\nexport async function runEnrichmentPipeline(\n df: DG.DataFrame,\n fcThreshold: number,\n pThreshold: number,\n organismCode: string,\n sources: string[],\n smartFilterEnabled: boolean = true,\n maxTermsPerSource: number = 15,\n): Promise<{enrichmentDf: DG.DataFrame; mapped: number; total: number; unmapped: number}> {\n const cols = findProteomicsColumns(df);\n if (!cols.proteinId)\n throw new Error('No protein ID column found');\n if (!cols.log2fc || !cols.pValue)\n throw new Error('No log2FC or adjusted p-value columns found. Run Differential Expression first.');\n\n // Step 1: Get gene symbols (existing or mapped)\n let geneForRow: Map<number, string>;\n let mapped = 0;\n let total = 0;\n let unmapped = 0;\n\n if (cols.geneName) {\n // Use existing gene name column. Truthiness check covers null/empty;\n // skipping the redundant isNone() halves the bridge hops.\n geneForRow = new Map();\n const geneNameCol = cols.geneName;\n for (let i = 0; i < df.rowCount; i++) {\n const val = geneNameCol.get(i) as string | null;\n if (val) geneForRow.set(i, val);\n }\n mapped = geneForRow.size;\n total = df.rowCount;\n unmapped = total - mapped;\n } else {\n // Extract clean accessions and map via g:Convert\n const accToRows = new Map<string, number[]>();\n for (let i = 0; i < df.rowCount; i++) {\n const raw = cols.proteinId!.get(i) as string;\n const acc = parseAccession(raw);\n if (acc) {\n if (!accToRows.has(acc))\n accToRows.set(acc, []);\n accToRows.get(acc)!.push(i);\n }\n }\n\n const uniqueAccessions = [...accToRows.keys()];\n const convertResults = await gConvert(uniqueAccessions, organismCode);\n\n // Build accession -> gene symbol map (first match per accession)\n const accToGene = new Map<string, string>();\n for (const r of convertResults) {\n if (r.incoming && r.name && r.name !== 'N/A' && !accToGene.has(r.incoming))\n accToGene.set(r.incoming, r.name);\n }\n\n // Map rows to gene symbols\n geneForRow = new Map();\n for (const [acc, rows] of accToRows) {\n const gene = accToGene.get(acc);\n if (gene) {\n for (const row of rows)\n geneForRow.set(row, gene);\n }\n }\n\n // Add gene symbol column to main table. Materialize the row->gene array\n // first, then bulk-init the column to skip per-row set() bridge hops.\n const geneArr: string[] = new Array(df.rowCount).fill('');\n for (const [row, gene] of geneForRow)\n geneArr[row] = gene;\n\n const geneCol = df.columns.addNewString('Gene Symbol (mapped)');\n geneCol.semType = SEMTYPE.GENE_SYMBOL;\n geneCol.init((i) => geneArr[i]);\n\n mapped = accToGene.size;\n total = uniqueAccessions.length;\n unmapped = total - mapped;\n }\n\n // Step 2: Split significant genes by fc sign; background = all detected,\n // shared by both directional queries (CK-omics run_gprofiler_analysis).\n // Bulk-read the numeric columns once via getRawData (no per-row bridge hops).\n const fcRaw = cols.log2fc.getRawData() as Float32Array | Float64Array;\n const pRaw = cols.pValue.getRawData() as Float32Array | Float64Array;\n const {upGenes, downGenes, background: bgArray} =\n splitGenesByDirection(geneForRow, fcRaw, pRaw, fcThreshold, pThreshold);\n\n if (upGenes.length === 0 && downGenes.length === 0)\n throw new Error('No significant proteins found with the given thresholds');\n\n // Step 3: One g:GOSt call per non-empty direction, identical background.\n // A direction with zero genes is skipped (no empty-query request).\n // Pitfall 8: when smart filter is enabled, run it BEFORE buildEnrichmentDf so\n // the per-row Intersection strings are built from the kept-set indices and\n // never get reindexed after the fact.\n const directionDfs: DG.DataFrame[] = [];\n let upStats: SmartFilterStats | null = null;\n let downStats: SmartFilterStats | null = null;\n if (upGenes.length > 0) {\n let upResults = await gGOSt(upGenes, bgArray, organismCode, sources, pThreshold);\n if (smartFilterEnabled) {\n const filtered = applySmartPathwayFilter(upResults, maxTermsPerSource);\n upResults = filtered.kept;\n upStats = filtered.stats;\n }\n directionDfs.push(buildEnrichmentDf(upResults, upGenes, pThreshold, 'Up'));\n }\n if (downGenes.length > 0) {\n let downResults = await gGOSt(downGenes, bgArray, organismCode, sources, pThreshold);\n if (smartFilterEnabled) {\n const filtered = applySmartPathwayFilter(downResults, maxTermsPerSource);\n downResults = filtered.kept;\n downStats = filtered.stats;\n }\n directionDfs.push(buildEnrichmentDf(downResults, downGenes, pThreshold, 'Down'));\n }\n\n // Step 4: Merge directional results into one DataFrame. Phase-9 column shape\n // is intact (Direction is just an extra categorical). append() returns a NEW\n // frame and may drop frame/column metadata, so re-apply the enrichment tag,\n // name, and FDR color-coding the viewers/cross-link key on.\n let enrichmentDf = directionDfs[0];\n for (let i = 1; i < directionDfs.length; i++)\n enrichmentDf = enrichmentDf.append(directionDfs[i]);\n // Name the result after its source table (e.g. \"MyStudy — Enrichment\") so it's\n // distinguishable when several analyses are open — mirrors the \"<source> — QC\"\n // convention. Falls back to the generic name if the source is unnamed.\n enrichmentDf.name = df.name ? `${df.name} — Enrichment` : 'Enrichment Results';\n enrichmentDf.setTag('proteomics.enrichment', 'true');\n const fdrCol = enrichmentDf.col('FDR');\n if (fdrCol) {\n fdrCol.setTag('color-coding-type', 'Linear');\n fdrCol.setTag('color-coding-linear', '{\"0\":\"#2ecc71\",\"0.05\":\"#f39c12\",\"1\":\"#e74c3c\"}');\n }\n\n // D-14 — set the smart-filter banner tags only when the filter actually\n // dropped rows (kept < total). Banner is suppressed when the filter was off\n // OR when kept == total. Tag names mirror UI-SPEC §\"Enrichment table:\n // smart pathway filter banner\".\n if (smartFilterEnabled) {\n const totalInput = (upStats?.total ?? 0) + (downStats?.total ?? 0);\n const totalKept = (upStats?.kept ?? 0) + (downStats?.kept ?? 0);\n const totalDropped = (upStats?.droppedParents ?? 0) + (downStats?.droppedParents ?? 0);\n if (totalKept < totalInput) {\n enrichmentDf.setTag('proteomics.enrichment_smart_filtered', 'true');\n enrichmentDf.setTag('proteomics.enrichment_smart_filtered_kept', String(totalKept));\n enrichmentDf.setTag('proteomics.enrichment_smart_filtered_total', String(totalInput));\n enrichmentDf.setTag('proteomics.enrichment_smart_filtered_dropped_parents', String(totalDropped));\n enrichmentDf.setTag('proteomics.enrichment_smart_filtered_cap', String(maxTermsPerSource));\n }\n }\n\n return {enrichmentDf, mapped, total, unmapped};\n}\n\n// --- Dialog ---\n\nexport function showEnrichmentDialog(df: DG.DataFrame): void {\n if (!requireDifferentialExpression(df, 'Run Differential Expression first')) return;\n\n const cols = findProteomicsColumns(df);\n if (!cols.log2fc || !cols.pValue) {\n grok.shell.warning('No log2FC or p-value columns found');\n return;\n }\n\n const fcInput = ui.input.float('|log2FC| threshold', {value: DEFAULT_FC_THRESHOLD});\n fcInput.setTooltip('Minimum absolute fold change for significance');\n\n const pInput = ui.input.float('Adj. p-value threshold', {value: DEFAULT_P_THRESHOLD});\n pInput.setTooltip('Maximum adjusted p-value for significance');\n\n // Seed from the chosen/persisted organism, else auto-detect from the data's\n // organism column (covers the Candidates path, which skips Annotate), else human.\n // Sticky + shared with the subcellular-location fetch via the proteomics.organism tag.\n const seededDisplay = organismDisplayForCode(getOrganism(df) ?? detectOrganismCode(df));\n const organismInput = ui.input.choice('Organism', {\n value: (seededDisplay ?? 'Homo sapiens (Human)') as string,\n items: ORGANISM_LIST.map((o) => o.display) as unknown as string[],\n nullable: false,\n });\n\n // Enrichment source checkboxes\n const goBpInput = ui.input.bool('GO: Biological Process', {value: true});\n const goMfInput = ui.input.bool('GO: Molecular Function', {value: true});\n const goCcInput = ui.input.bool('GO: Cellular Component', {value: true});\n const keggInput = ui.input.bool('KEGG Pathways', {value: true});\n const reactomeInput = ui.input.bool('Reactome Pathways', {value: true});\n const wpInput = ui.input.bool('WikiPathways', {value: true});\n\n // D-14 — smart pathway filter checkbox, default checked.\n const smartFilterInput = ui.input.bool('Apply smart pathway filter', {value: true});\n smartFilterInput.setTooltip(\n 'Drops generic GO parent terms when more specific child terms are present; ' +\n 'caps each source at top-N by FDR. Recommended for cleaner results; ' +\n 'uncheck for raw g:Profiler output.');\n\n // M3 — the per-source top-N cap the smart filter applies (was hardcoded 15).\n // Only meaningful when the smart filter is on; greyed out otherwise.\n const maxTermsInput = ui.input.int('Max terms per source', {value: 15, min: 1});\n maxTermsInput.setTooltip(\n 'Upper bound on terms kept per enrichment source (top-N by FDR). ' +\n 'Applies only when the smart pathway filter is on.');\n const syncMaxTermsEnabled = () => maxTermsInput.enabled = smartFilterInput.value ?? true;\n smartFilterInput.onChanged.subscribe(syncMaxTermsEnabled);\n syncMaxTermsEnabled();\n\n // Live count of significant proteins\n const countDiv = ui.divText('');\n const updateCount = () => {\n const fc = fcInput.value ?? DEFAULT_FC_THRESHOLD;\n const p = pInput.value ?? DEFAULT_P_THRESHOLD;\n const result = countSignificantProteins(df, fc, p, cols.log2fc!, cols.pValue!);\n const totalFmt = result.total.toLocaleString();\n countDiv.textContent =\n `${result.significant} of ${totalFmt} proteins are significant with these thresholds`;\n };\n updateCount();\n fcInput.onChanged.subscribe(updateCount);\n pInput.onChanged.subscribe(updateCount);\n\n ui.dialog('Enrichment Analysis')\n .add(countDiv)\n .add(fcInput)\n .add(pInput)\n .add(organismInput)\n .add(goBpInput)\n .add(goMfInput)\n .add(goCcInput)\n .add(keggInput)\n .add(reactomeInput)\n .add(wpInput)\n .add(smartFilterInput)\n .add(maxTermsInput)\n .onOK(async () => {\n const pi = DG.TaskBarProgressIndicator.create('Running enrichment analysis...');\n try {\n const fc = fcInput.value ?? DEFAULT_FC_THRESHOLD;\n const p = pInput.value ?? DEFAULT_P_THRESHOLD;\n\n // Resolve organism code from display name\n const selectedDisplay = organismInput.value;\n const organism = ORGANISM_LIST.find((o) => o.display === selectedDisplay);\n const organismCode = organism?.code ?? 'hsapiens';\n // Persist so the subcellular-location fetch (and next enrichment run)\n // narrow to the same species.\n setOrganism(df, organismCode);\n\n // Build sources array from checkbox states\n const selectedSources: string[] = [];\n if (goBpInput.value) selectedSources.push('GO:BP');\n if (goMfInput.value) selectedSources.push('GO:MF');\n if (goCcInput.value) selectedSources.push('GO:CC');\n if (keggInput.value) selectedSources.push('KEGG');\n if (reactomeInput.value) selectedSources.push('REAC');\n if (wpInput.value) selectedSources.push('WP');\n\n if (selectedSources.length === 0) {\n grok.shell.warning('Please select at least one enrichment source');\n return;\n }\n\n const result = await runEnrichmentPipeline(\n df, fc, p, organismCode, selectedSources, smartFilterInput.value ?? true,\n maxTermsInput.value ?? 15);\n\n // Show mapping stats\n const pct = result.total > 0 ? (result.mapped / result.total * 100).toFixed(1) : '0.0';\n grok.shell.info(\n `${result.mapped}/${result.total} proteins mapped (${pct}%). ${result.unmapped} unmapped.`,\n );\n\n // openEnrichmentVisualization creates (or reuses) the enrichment results\n // view itself — adding one here too spawned a duplicate \"Enrichment\n // Results (2)\" tab every run.\n openEnrichmentVisualization(result.enrichmentDf, df);\n } catch (e: any) {\n grok.shell.error(`Enrichment analysis failed: ${e.message}`);\n } finally {\n pi.close();\n }\n })\n .show();\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\nimport dayjs from 'dayjs';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {RunMeta, setRunMeta, getRunMeta} from './spc';\nimport {ORGANISM_LIST, detectOrganismCode, organismDisplayForCode,\n organismCodeForDisplay} from '../utils/organisms';\n\n/** Describes which intensity columns belong to each experimental group. */\nexport interface GroupAssignment {\n group1: {name: string; columns: string[]};\n group2: {name: string; columns: string[]};\n}\n\n/** Store group assignments as a DataFrame tag. */\nexport function setGroups(df: DG.DataFrame, groups: GroupAssignment): void {\n df.setTag('proteomics.groups', JSON.stringify(groups));\n}\n\n/** Retrieve group assignments from DataFrame tag. Returns null if not set. */\nexport function getGroups(df: DG.DataFrame): GroupAssignment | null {\n const raw = df.getTag('proteomics.groups');\n if (!raw) return null;\n try {\n return JSON.parse(raw) as GroupAssignment;\n } catch {\n return null;\n }\n}\n\n/** Store the experiment's organism as a g:Profiler code (e.g. `rnorvegicus`) on\n * the DataFrame. Single source of truth shared by enrichment and the subcellular-\n * location fetch — set once (enrichment dialog OK), read by both. */\nexport function setOrganism(df: DG.DataFrame, code: string): void {\n df.setTag('proteomics.organism', code);\n}\n\n/** Retrieve the experiment's organism code, or undefined if never chosen. The\n * subcellular-location gene fallback narrows by this; undefined = unfiltered\n * (safe — same behavior as before an organism was ever selected). */\nexport function getOrganism(df: DG.DataFrame): string | undefined {\n return df.getTag('proteomics.organism') || undefined;\n}\n\n/** Seed values for the Annotate Experiment dialog. */\nexport interface AnnotationSeed {\n group1Name: string;\n group1Cols: DG.Column[];\n group2Name: string;\n group2Cols: DG.Column[];\n /** Phase 16 D-01: persisted operator value, else parser-side seed, else undefined. */\n instrumentId?: string;\n /** Phase 16 D-01: ISO-8601 (date-only acceptable per RESEARCH gotcha #1). */\n acquisitionDatetime?: string;\n}\n\n/**\n * Seeds Annotate Experiment dialog inputs from existing `proteomics.groups` if present,\n * else returns the legacy Control/Treatment defaults. Stale column refs (no longer in the\n * DataFrame or in the `available` list) are silently dropped — protects parser-populated\n * assignments (e.g. Spectronaut DMD/WT) from being blanked when the user OKs the dialog\n * without re-selecting columns.\n */\nexport function seedAnnotationDialogInputs(df: DG.DataFrame, available: string[]): AnnotationSeed {\n const runMetaSeed = readRunMetaSeed(df);\n const existing = getGroups(df);\n if (!existing) {\n return {\n group1Name: 'Control', group1Cols: [],\n group2Name: 'Treatment', group2Cols: [],\n instrumentId: runMetaSeed?.instrument_id,\n acquisitionDatetime: runMetaSeed?.acquisition_datetime,\n };\n }\n const availableSet = new Set(available);\n const resolve = (names: string[]): DG.Column[] => names\n .filter((n) => availableSet.has(n))\n .map((n) => df.col(n))\n .filter((c): c is DG.Column => c !== null);\n return {\n group1Name: existing.group1.name || 'Control',\n group1Cols: resolve(existing.group1.columns),\n group2Name: existing.group2.name || 'Treatment',\n group2Cols: resolve(existing.group2.columns),\n instrumentId: runMetaSeed?.instrument_id,\n acquisitionDatetime: runMetaSeed?.acquisition_datetime,\n };\n}\n\n/** Reads the Phase 16 run-identity seed in priority order:\n * 1. Persisted `proteomics.spc_run_meta` (operator value from a prior dialog OK)\n * 2. Parser-side `proteomics.spc_run_meta_seed` (set by the Spectronaut PG parser)\n * 3. undefined (operator types both fields manually)\n */\nfunction readRunMetaSeed(df: DG.DataFrame): RunMeta | undefined {\n const persisted = getRunMeta(df);\n if (persisted) return persisted;\n const raw = df.getTag('proteomics.spc_run_meta_seed');\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as RunMeta;\n } catch {\n return undefined;\n }\n}\n\n/** Shows a dialog for assigning intensity columns to two experimental groups. */\nexport function showAnnotationDialog(df: DG.DataFrame): void {\n const intensityColNames = df.columns.toList()\n .filter((c) => c.semType === SEMTYPE.INTENSITY && c.name.startsWith('log2('))\n .map((c) => c.name);\n\n const seed = seedAnnotationDialogInputs(df, intensityColNames);\n\n const group1Name = ui.input.string('Group 1 Name', {value: seed.group1Name});\n const group1Cols = ui.input.columns('Group 1', {table: df, available: intensityColNames, value: seed.group1Cols});\n const group2Name = ui.input.string('Group 2 Name', {value: seed.group2Name});\n const group2Cols = ui.input.columns('Group 2', {table: df, available: intensityColNames, value: seed.group2Cols});\n // Phase 16 D-01: two new optional run-identity inputs. Tooltips come VERBATIM from UI-SPEC.\n const instrumentInput = ui.input.string('Instrument', {\n value: seed.instrumentId ?? '',\n tooltipText: 'Free-text identifier for the instrument that ran this analysis (e.g. QExactive-01). ' +\n 'Used to group runs in the SPC dashboard.',\n });\n const datetimeInput = ui.input.date('Acquisition datetime', {\n value: seed.acquisitionDatetime ? dayjs(seed.acquisitionDatetime) : null,\n tooltipText: 'When the samples were acquired on the instrument. ' +\n 'Used to order runs on the SPC trend chart — not the file-import time.',\n } as any);\n // Organism: persisted choice, else auto-detected from the data's organism\n // column, else human. Sets proteomics.organism early so enrichment and the\n // subcellular-location fetch narrow to the right species (not always human).\n const organismInput = ui.input.choice('Organism', {\n value: (organismDisplayForCode(getOrganism(df) ?? detectOrganismCode(df)) ??\n 'Homo sapiens (Human)') as string,\n items: ORGANISM_LIST.map((o) => o.display) as unknown as string[],\n nullable: false,\n tooltipText: 'Species for enrichment (g:Profiler) and UniProt subcellular-location ' +\n 'lookup. Auto-detected from the data when available.',\n });\n\n ui.dialog('Annotate Experiment')\n .add(group1Name)\n .add(group1Cols)\n .add(group2Name)\n .add(group2Cols)\n .add(organismInput)\n .add(instrumentInput)\n .add(datetimeInput)\n .onOK(() => {\n const g1: DG.Column[] = group1Cols.value ?? [];\n const g2: DG.Column[] = group2Cols.value ?? [];\n\n if (g1.length === 0 || g2.length === 0) {\n grok.shell.warning('Select at least one column per group');\n return;\n }\n\n const groups: GroupAssignment = {\n group1: {name: group1Name.value, columns: g1.map((c) => c.name)},\n group2: {name: group2Name.value, columns: g2.map((c) => c.name)},\n };\n const instrumentValue = (instrumentInput.value ?? '').trim();\n const datetimeValue: any = datetimeInput.value;\n const isoDatetime = datetimeValue && typeof datetimeValue.toISOString === 'function'\n ? datetimeValue.toISOString()\n : (datetimeValue instanceof Date ? datetimeValue.toISOString() : '');\n applyAnnotation(df, {\n group1: groups.group1,\n group2: groups.group2,\n organism: organismCodeForDisplay(organismInput.value ?? undefined),\n runMeta: (instrumentValue.length > 0 || isoDatetime.length > 0)\n ? {instrument_id: instrumentValue, acquisition_datetime: isoDatetime}\n : undefined,\n });\n grok.shell.info(`Groups assigned: ${g1.length} + ${g2.length} samples`);\n })\n .show();\n}\n\n/** Programmatic Annotate Experiment OK-path. Used by Plan 16-01's\n * `SPC:annotation_dialog_persists_run_meta` test and by the dialog above to\n * share the persist-on-OK flow. setGroups + setRunMeta in lockstep so the\n * test never has to instantiate a real dialog. */\nexport function applyAnnotation(\n df: DG.DataFrame,\n payload: {\n group1: GroupAssignment['group1'];\n group2: GroupAssignment['group2'];\n organism?: string;\n runMeta?: RunMeta;\n },\n): void {\n setGroups(df, {group1: payload.group1, group2: payload.group2});\n if (payload.organism) setOrganism(df, payload.organism);\n if (payload.runMeta) setRunMeta(df, payload.runMeta);\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {getGroups} from './experiment-setup';\n\n/** Generates a random number from a normal distribution using Box-Muller transform. */\nfunction randomNormal(mean: number, stdev: number): number {\n const u1 = Math.random();\n const u2 = Math.random();\n const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n return mean + stdev * z;\n}\n\n/** Imputes missing values using the MinProb method (Perseus-style).\n * Draws random values from a downshifted normal distribution\n * simulating low-abundance proteins below detection limit.\n * Returns the total number of imputed values. */\nexport function imputeMinProb(\n df: DG.DataFrame,\n colNames: string[],\n downshift: number = 1.8,\n width: number = 0.3,\n): number {\n let totalImputed = 0;\n\n for (const name of colNames) {\n const col = df.col(name);\n if (!col) continue;\n if (col.type !== DG.COLUMN_TYPE.FLOAT) continue;\n\n const avg = col.stats.avg;\n const stdev = col.stats.stdev;\n if (isNaN(avg) || isNaN(stdev) || stdev === 0) continue;\n\n const imputeMean = avg - downshift * stdev;\n const imputeSd = width * stdev;\n\n const raw = col.getRawData() as Float32Array | Float64Array;\n for (let i = 0; i < df.rowCount; i++) {\n if (raw[i] === DG.FLOAT_NULL) {\n raw[i] = randomNormal(imputeMean, imputeSd);\n totalImputed++;\n }\n }\n }\n\n df.fireValuesChanged();\n df.setTag('proteomics.imputed', 'true');\n return totalImputed;\n}\n\n/** Imputes missing values using k-nearest neighbor averaging.\n * For each row with missing values, finds the k nearest rows by mean-squared\n * distance (RMSE) over the columns where both rows have valid values, then\n * averages those neighbors' values. Normalizing by sharedCount keeps distances\n * comparable across rows with different numbers of shared observations.\n * Falls back to the column mean when no neighbors have values for a column;\n * if a column is entirely missing, leaves the cell null.\n * Shows a progress indicator during computation.\n * Returns the total number of imputed values. */\nexport function imputeKnn(\n df: DG.DataFrame,\n colNames: string[],\n k: number = 10,\n): number {\n const cols = colNames.map((n) => df.col(n)).filter((c) => c != null && c.type === DG.COLUMN_TYPE.FLOAT) as DG.Column[];\n if (cols.length === 0) return 0;\n\n // Cache the underlying typed arrays for direct in-place writes — avoids the\n // JS→native bridge per cell in the inner imputation loops below.\n const rawArrays = cols.map((c) => c.getRawData() as Float32Array | Float64Array);\n\n const nRows = df.rowCount;\n const nCols = cols.length;\n\n // Build matrix and missing mask\n const matrix: Float64Array[] = [];\n const missing: boolean[][] = [];\n for (let r = 0; r < nRows; r++) {\n const row = new Float64Array(nCols);\n const miss: boolean[] = [];\n for (let c = 0; c < nCols; c++) {\n const isNull = cols[c].isNone(r);\n miss.push(isNull);\n row[c] = isNull ? 0 : cols[c].get(r);\n }\n matrix.push(row);\n missing.push(miss);\n }\n\n // Compute column means (from non-missing values) as fallback.\n // Use NaN for all-missing columns so downstream consumers can detect \"no signal\"\n // rather than silently filling missing cells with a literal 0 (a valid log2 intensity).\n const colMeans = new Float64Array(nCols);\n for (let c = 0; c < nCols; c++) {\n let sum = 0;\n let count = 0;\n for (let r = 0; r < nRows; r++) {\n if (!missing[r][c]) {\n sum += matrix[r][c];\n count++;\n }\n }\n colMeans[c] = count > 0 ? sum / count : NaN;\n }\n\n // Find rows with any missing values (regardless of whether they also have valid ones —\n // the all-missing case is handled inside the loop via column means or null).\n const rowsWithMissing: number[] = [];\n for (let r = 0; r < nRows; r++) {\n if (missing[r].some((m) => m))\n rowsWithMissing.push(r);\n }\n\n const pi = DG.TaskBarProgressIndicator.create('kNN imputation...');\n let totalImputed = 0;\n\n try {\n for (let idx = 0; idx < rowsWithMissing.length; idx++) {\n const r = rowsWithMissing[idx];\n pi.update(Math.round((idx / rowsWithMissing.length) * 100), `Row ${idx + 1}/${rowsWithMissing.length}`);\n\n // Check if this row has any valid values for distance computation\n const hasAnyValid = missing[r].some((m) => !m);\n\n if (!hasAnyValid) {\n // All-missing row: use column means, but leave null if the column itself was all-missing\n for (let c = 0; c < nCols; c++) {\n if (missing[r][c] && isFinite(colMeans[c])) {\n rawArrays[c][r] = colMeans[c];\n totalImputed++;\n }\n }\n continue;\n }\n\n // Compute distances to all other rows on shared non-missing columns\n const distances: {row: number; dist: number}[] = [];\n for (let other = 0; other < nRows; other++) {\n if (other === r) continue;\n\n let sumSq = 0;\n let sharedCount = 0;\n for (let c = 0; c < nCols; c++) {\n if (!missing[r][c] && !missing[other][c]) {\n const diff = matrix[r][c] - matrix[other][c];\n sumSq += diff * diff;\n sharedCount++;\n }\n }\n\n if (sharedCount > 0)\n distances.push({row: other, dist: Math.sqrt(sumSq / sharedCount)});\n }\n\n // Sort by distance, take top k\n distances.sort((a, b) => a.dist - b.dist);\n const neighbors = distances.slice(0, k);\n\n // For each missing column in this row, average neighbors' values\n for (let c = 0; c < nCols; c++) {\n if (!missing[r][c]) continue;\n\n let sum = 0;\n let count = 0;\n for (const n of neighbors) {\n if (!missing[n.row][c]) {\n sum += matrix[n.row][c];\n count++;\n }\n }\n\n const val = count > 0 ? sum / count : colMeans[c];\n if (isFinite(val)) {\n rawArrays[c][r] = val;\n totalImputed++;\n }\n }\n }\n } finally {\n pi.close();\n }\n\n df.fireValuesChanged();\n df.setTag('proteomics.imputed', 'true');\n return totalImputed;\n}\n\n/** Imputes missing values by replacing them with zero.\n * Returns the total number of imputed values. */\nexport function imputeZero(df: DG.DataFrame, colNames: string[]): number {\n let totalImputed = 0;\n for (const name of colNames) {\n const col = df.col(name);\n if (!col || col.type !== DG.COLUMN_TYPE.FLOAT) continue;\n const raw = col.getRawData() as Float32Array | Float64Array;\n for (let i = 0; i < df.rowCount; i++) {\n if (raw[i] === DG.FLOAT_NULL) {\n raw[i] = 0;\n totalImputed++;\n }\n }\n }\n df.fireValuesChanged();\n df.setTag('proteomics.imputed', 'true');\n return totalImputed;\n}\n\n/** Imputes missing values by replacing them with the column mean.\n * Returns the total number of imputed values. */\nexport function imputeMean(df: DG.DataFrame, colNames: string[]): number {\n let totalImputed = 0;\n for (const name of colNames) {\n const col = df.col(name);\n if (!col || col.type !== DG.COLUMN_TYPE.FLOAT) continue;\n const avg = col.stats.avg;\n if (isNaN(avg)) continue;\n const raw = col.getRawData() as Float32Array | Float64Array;\n for (let i = 0; i < df.rowCount; i++) {\n if (raw[i] === DG.FLOAT_NULL) {\n raw[i] = avg;\n totalImputed++;\n }\n }\n }\n df.fireValuesChanged();\n df.setTag('proteomics.imputed', 'true');\n return totalImputed;\n}\n\n/** Imputes missing values by replacing them with the column median.\n * Returns the total number of imputed values. */\nexport function imputeMedian(df: DG.DataFrame, colNames: string[]): number {\n let totalImputed = 0;\n for (const name of colNames) {\n const col = df.col(name);\n if (!col || col.type !== DG.COLUMN_TYPE.FLOAT) continue;\n const med = col.stats.med;\n if (isNaN(med)) continue;\n const raw = col.getRawData() as Float32Array | Float64Array;\n for (let i = 0; i < df.rowCount; i++) {\n if (raw[i] === DG.FLOAT_NULL) {\n raw[i] = med;\n totalImputed++;\n }\n }\n }\n df.fireValuesChanged();\n df.setTag('proteomics.imputed', 'true');\n return totalImputed;\n}\n\n/** Shows a dialog for imputing missing values with method selection,\n * conditional parameters, and valid-values protein filter. */\nexport function showImputationDialog(df: DG.DataFrame): void {\n if (df.getTag('proteomics.imputed') === 'true') {\n grok.shell.warning('Missing values already imputed');\n return;\n }\n\n const log2ColNames = df.columns.toList()\n .filter((c) => c.semType === SEMTYPE.INTENSITY && c.name.startsWith('log2('))\n .map((c) => c.name);\n\n const log2Cols = log2ColNames.map((n) => df.col(n)!);\n\n // Method selector\n const methodInput = ui.input.choice('Method', {\n value: 'MinProb',\n items: ['MinProb', 'kNN', 'Zero', 'Mean', 'Median'],\n nullable: false,\n });\n\n // Column picker\n const colsInput = ui.input.columns('Intensity columns', {\n table: df, available: log2ColNames, value: log2Cols,\n });\n\n // MinProb-specific inputs\n const downshiftInput = ui.input.float('Downshift', {value: 1.8});\n downshiftInput.setTooltip('Standard deviations to shift left from mean (Perseus default: 1.8)');\n const widthInput = ui.input.float('Width', {value: 0.3});\n widthInput.setTooltip('Fraction of standard deviation for imputation distribution (Perseus default: 0.3)');\n const minProbContainer = ui.div([downshiftInput.root, widthInput.root]);\n\n // kNN-specific input\n const kInput = ui.input.int('k (neighbors)', {value: 10});\n const knnContainer = ui.div([kInput.root]);\n knnContainer.style.display = 'none';\n\n // Toggle visibility based on method\n methodInput.onChanged.subscribe(() => {\n const method = methodInput.value;\n minProbContainer.style.display = method === 'MinProb' ? '' : 'none';\n knnContainer.style.display = method === 'kNN' ? '' : 'none';\n });\n\n // Valid-values filter\n const minValidInput = ui.input.int('Min valid values per group', {value: 2});\n const filterCountDiv = ui.divText('');\n filterCountDiv.style.cssText = 'font-size:12px; color:#888; margin-bottom:8px;';\n\n const updateFilterCount = () => {\n const threshold = minValidInput.value ?? 0;\n const groups = getGroups(df);\n if (threshold === 0 || !groups) {\n filterCountDiv.textContent = `Will keep all ${df.rowCount} proteins`;\n return;\n }\n\n const g1Cols = groups.group1.columns.map((n) => df.col(n)).filter((c) => c != null) as DG.Column[];\n const g2Cols = groups.group2.columns.map((n) => df.col(n)).filter((c) => c != null) as DG.Column[];\n let kept = 0;\n\n for (let r = 0; r < df.rowCount; r++) {\n let g1Valid = 0;\n for (const col of g1Cols) {\n if (!col.isNone(r)) g1Valid++;\n }\n let g2Valid = 0;\n for (const col of g2Cols) {\n if (!col.isNone(r)) g2Valid++;\n }\n // Protein passes if ANY group has >= threshold valid values\n if (g1Valid >= threshold || g2Valid >= threshold)\n kept++;\n }\n\n const removed = df.rowCount - kept;\n filterCountDiv.textContent = `Will keep ${kept}/${df.rowCount} proteins (${removed} removed)`;\n };\n\n minValidInput.onChanged.subscribe(updateFilterCount);\n updateFilterCount();\n\n ui.dialog('Impute Missing Values')\n .add(methodInput)\n .add(colsInput)\n .add(minProbContainer)\n .add(knnContainer)\n .add(minValidInput)\n .add(filterCountDiv)\n .onOK(() => {\n const selected = colsInput.value.map((c: DG.Column) => c.name);\n const method = methodInput.value;\n\n // Apply valid-values filter if threshold > 0 and groups exist\n const threshold = minValidInput.value ?? 0;\n const groups = getGroups(df);\n if (threshold > 0 && groups) {\n const g1Cols = groups.group1.columns.map((n) => df.col(n)).filter((c) => c != null) as DG.Column[];\n const g2Cols = groups.group2.columns.map((n) => df.col(n)).filter((c) => c != null) as DG.Column[];\n const removeSet = DG.BitSet.create(df.rowCount);\n\n for (let r = 0; r < df.rowCount; r++) {\n let g1Valid = 0;\n for (const col of g1Cols) {\n if (!col.isNone(r)) g1Valid++;\n }\n let g2Valid = 0;\n for (const col of g2Cols) {\n if (!col.isNone(r)) g2Valid++;\n }\n if (g1Valid < threshold && g2Valid < threshold)\n removeSet.set(r, true);\n }\n\n const removed = removeSet.trueCount;\n if (removed > 0) {\n df.rows.removeWhere((row) => removeSet.get(row.idx));\n grok.shell.info(`Filtered: removed ${removed} proteins below threshold`);\n }\n }\n\n // Dispatch to selected imputation method. Imputation runs AFTER the valid-values\n // filter above, which has already mutated df.rows — if imputation throws, the\n // filter cannot be reverted, so surface the partial state clearly.\n let count = 0;\n try {\n switch (method) {\n case 'MinProb':\n count = imputeMinProb(df, selected, downshiftInput.value!, widthInput.value!);\n break;\n case 'kNN':\n count = imputeKnn(df, selected, kInput.value!);\n break;\n case 'Zero':\n count = imputeZero(df, selected);\n break;\n case 'Mean':\n count = imputeMean(df, selected);\n break;\n case 'Median':\n count = imputeMedian(df, selected);\n break;\n }\n } catch (e: any) {\n grok.shell.error(`Imputation failed: ${e?.message ?? e}. Valid-values filter was already applied; data remains filtered but un-imputed.`);\n return;\n }\n\n grok.shell.info(`Imputed ${count} missing values across ${selected.length} columns (${method})`);\n })\n .show();\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {log2TransformColumns, copyAsLog2Columns, detectLog2Status} from '../parsers/shared-utils';\n\n/**\n * Post-import correction for the log2 scale of intensity data.\n *\n * At import each parser decides whether the intensities are raw (needs a log2\n * transform) or already log2-transformed (copy as-is). That decision is a\n * magnitude heuristic (`detectLog2Status`) and has misfired on small-magnitude\n * linear intensities — values that happen to sit in the [0, 30] \"looks like\n * log2\" band get copied instead of transformed, producing nonsense ±thousands\n * fold changes downstream. This module lets the analyst override that call\n * without re-importing.\n *\n * The rebuild works off the ORIGINAL (non-`log2(...)`) intensity columns, which\n * every parser keeps pristine — normalization/imputation only ever mutate the\n * `log2(...)` copies in place. So re-deriving the `log2(...)` columns is always\n * valid and, by design, discards any normalization/imputation/DE that ran on the\n * old values; those steps must be re-run, which the dialog warns about.\n */\n\n/** Original (pre-`log2(...)`) intensity column names — the pristine source the\n * rebuild derives from. Excludes the `log2(...)` copies themselves. */\nexport function getIntensityOriginals(df: DG.DataFrame): string[] {\n return df.columns.toList()\n .filter((c) => c.semType === SEMTYPE.INTENSITY && !c.name.startsWith('log2('))\n .map((c) => c.name);\n}\n\n/** Infers whether the current `log2(...)` columns were produced by a transform\n * (`Math.log2(orig)`) or a straight copy (`orig`, i.e. treated as already log2).\n * Scans until the first decisive non-null positive row — the two branches never\n * coincide for a positive value (`log2(x) ≠ x` for all x > 0). Returns 'unknown'\n * when no `log2(...)` column or no decisive row exists. */\nexport function detectCurrentLog2Applied(\n df: DG.DataFrame, originalNames: string[],\n): 'transform' | 'copy' | 'unknown' {\n for (const name of originalNames) {\n const orig = df.col(name);\n const l2 = df.col(`log2(${name})`);\n if (!orig || !l2) continue;\n for (let i = 0; i < df.rowCount; i++) {\n if (orig.isNone(i) || l2.isNone(i)) continue;\n const o = Number(orig.get(i));\n const v = Number(l2.get(i));\n if (!(o > 0) || !Number.isFinite(v)) continue;\n if (Math.abs(v - Math.log2(o)) < 1e-4) return 'transform';\n if (Math.abs(v - o) < 1e-4) return 'copy';\n }\n }\n return 'unknown';\n}\n\n/** Rebuilds the `log2(...)` columns from the originals under the chosen scale:\n * `alreadyLog2` copies as-is, otherwise applies the log2 transform. Removes the\n * existing `log2(...)` columns first (so a re-run doesn't duplicate) and clears\n * stale downstream pipeline tags — the base data changed, so any prior\n * normalize/impute/DE is invalid and must be re-run. No-op (returns false) when\n * the requested scale already matches what's applied. */\nexport function applyLog2Scale(df: DG.DataFrame, alreadyLog2: boolean): boolean {\n const originals = getIntensityOriginals(df);\n if (originals.length === 0) return false;\n\n const current = detectCurrentLog2Applied(df, originals);\n const target = alreadyLog2 ? 'copy' : 'transform';\n if (current === target) return false;\n\n for (const name of originals) {\n const l2 = `log2(${name})`;\n if (df.col(l2)) df.columns.remove(l2);\n }\n if (alreadyLog2)\n copyAsLog2Columns(df, originals);\n else\n log2TransformColumns(df, originals);\n\n // Base intensities were re-derived — anything computed from the old log2\n // columns is stale. Drop the completion tags so viewers gate correctly and\n // the analyst re-runs from Normalize.\n for (const tag of ['proteomics.normalized', 'proteomics.imputed',\n 'proteomics.de_complete', 'proteomics.de_method'])\n df.setTag(tag, '');\n return true;\n}\n\n/** Dialog to review and override the log2 scale of the imported intensities.\n * Seeds the checkbox from the scale actually applied at import (inferred), not a\n * re-detection, so it reflects reality; shows the magnitude heuristic's read as\n * an advisory hint. */\nexport function showLog2ScaleDialog(df: DG.DataFrame): void {\n const originals = getIntensityOriginals(df);\n if (originals.length === 0) {\n grok.shell.warning('No intensity columns found — nothing to rescale.');\n return;\n }\n\n const current = detectCurrentLog2Applied(df, originals);\n const detection = detectLog2Status(df, originals);\n\n const alreadyLog2 = ui.input.bool('Data is already log2-transformed', {\n value: current === 'copy',\n tooltipText: 'On: intensities are used as-is. Off: a log2 transform is applied. ' +\n 'Flip this if fold changes look wildly off — the import heuristic can misread ' +\n 'small-magnitude raw intensities as already-log2.',\n });\n\n const hint = ui.divText(`Auto-detection: ${detection.message}.` +\n (current !== 'unknown' ? ` Currently applied: ${current === 'copy' ?\n 'used as-is (no transform)' : 'log2-transformed'}.` : ''));\n hint.style.cssText = 'font-style:italic;color:#888;margin:4px 0;font-size:12px;max-width:420px;';\n\n const pipelineRan = ['proteomics.normalized', 'proteomics.imputed', 'proteomics.de_complete']\n .some((t) => df.getTag(t) === 'true');\n const warn = ui.divText(\n 'Normalize / Impute / Differential Expression have already run. Changing the ' +\n 'scale resets those steps — re-run them from Analyze.');\n warn.style.cssText = 'color:#b26a00;margin:4px 0;font-size:12px;max-width:420px;';\n warn.style.display = pipelineRan ? '' : 'none';\n\n ui.dialog('Set Log2 Scale')\n .add(alreadyLog2)\n .add(hint)\n .add(warn)\n .onOK(() => {\n const changed = applyLog2Scale(df, alreadyLog2.value);\n if (!changed) {\n grok.shell.info('Scale unchanged.');\n return;\n }\n grok.shell.info(alreadyLog2.value ?\n 'Intensities are now used as-is (no log2 transform). Re-run analysis steps.' :\n 'Intensities are now log2-transformed. Re-run analysis steps.');\n })\n .show();\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {unpivotIntensities} from '../viewers/qc-computations';\n\n/** Median-centers each specified column in-place.\n * Subtracts the column median from every non-null value.\n * Uses getRawData() for bulk array access instead of per-element get/set. */\nexport function medianNormalize(df: DG.DataFrame, colNames: string[]): void {\n for (const name of colNames) {\n const col = df.col(name);\n if (!col) continue;\n if (col.type !== DG.COLUMN_TYPE.FLOAT) {\n console.warn(`medianNormalize: skipping non-float column \"${name}\" (type=${col.type})`);\n continue;\n }\n\n const median = col.stats.med;\n if (isNaN(median)) continue;\n\n const raw = col.getRawData() as Float32Array | Float64Array;\n for (let i = 0; i < raw.length; i++) {\n if (!col.isNone(i))\n raw[i] -= median;\n }\n }\n df.fireValuesChanged();\n df.setTag('proteomics.normalized', 'true');\n}\n\n/** Quantile-normalizes the specified columns in-place.\n * Aligns all column distributions to the same shape by replacing values\n * with rank-based averages. Missing values are preserved.\n * Uses getRawData() for bulk array access in tight loops. */\nexport function quantileNormalize(df: DG.DataFrame, colNames: string[]): void {\n if (colNames.length < 2) return;\n\n const cols = colNames.map((n) => df.col(n))\n .filter((c) => c != null && c.type === DG.COLUMN_TYPE.FLOAT) as DG.Column[];\n if (cols.length < 2) return;\n\n const nRows = df.rowCount;\n\n // For each column, collect indices of non-missing values and sort by value\n const colData: {indices: number[]; raw: Float32Array | Float64Array}[] = [];\n for (const col of cols) {\n const raw = col.getRawData() as Float32Array | Float64Array;\n const indices: number[] = [];\n for (let i = 0; i < nRows; i++) {\n if (!col.isNone(i))\n indices.push(i);\n }\n // Sort indices by value (ascending)\n indices.sort((a, b) => raw[a] - raw[b]);\n colData.push({indices, raw});\n }\n\n // Find the maximum number of non-null values across columns\n const maxValid = Math.max(...colData.map((d) => d.indices.length));\n if (maxValid === 0) return;\n\n // Compute rank means using scaled rank alignment\n // For each rank position r (0..maxValid-1), compute the mean of values\n // at the corresponding fractional position in each column\n const rankMeans = new Float64Array(maxValid);\n for (let r = 0; r < maxValid; r++) {\n let sum = 0;\n let count = 0;\n for (const d of colData) {\n if (d.indices.length === 0) continue;\n // Map rank r in [0..maxValid-1] to position in this column's sorted values\n const pos = (r / (maxValid - 1)) * (d.indices.length - 1);\n // Interpolate between floor and ceil positions\n const lo = Math.floor(pos);\n const hi = Math.min(Math.ceil(pos), d.indices.length - 1);\n const frac = pos - lo;\n const val = (1 - frac) * d.raw[d.indices[lo]] + frac * d.raw[d.indices[hi]];\n sum += val;\n count++;\n }\n rankMeans[r] = sum / count;\n }\n\n // Replace each column's sorted values with the corresponding rank mean\n for (const d of colData) {\n const n = d.indices.length;\n if (n === 0) continue;\n for (let r = 0; r < n; r++) {\n // Map this column's rank to the global rank mean position\n const globalPos = maxValid === 1 ? 0 : (r / (n - 1)) * (maxValid - 1);\n const lo = Math.floor(globalPos);\n const hi = Math.min(Math.ceil(globalPos), maxValid - 1);\n const frac = globalPos - lo;\n const val = (1 - frac) * rankMeans[lo] + frac * rankMeans[hi];\n d.raw[d.indices[r]] = val;\n }\n }\n\n df.fireValuesChanged();\n df.setTag('proteomics.normalized', 'true');\n}\n\n/** Performs Variance-Stabilizing Normalization via server-side R script.\n * Operates on raw (non-log2) intensity columns and writes results to log2 columns.\n * Falls back to quantile normalization if R environment is unavailable. */\nexport async function vsnNormalize(df: DG.DataFrame, colNames: string[]): Promise<void> {\n try {\n // Find raw intensity column names by stripping log2() prefix\n const rawColNames: string[] = [];\n const log2ColNames: string[] = [];\n for (const name of colNames) {\n if (name.startsWith('log2(') && name.endsWith(')')) {\n const rawName = name.slice(5, -1);\n if (df.col(rawName)) {\n rawColNames.push(rawName);\n log2ColNames.push(name);\n }\n }\n }\n\n if (rawColNames.length === 0) {\n // No raw columns found, fall back to quantile\n if (colNames.length < 2) {\n grok.shell.warning('Cannot normalize — VSN needs raw intensity columns and quantile fallback needs at least 2 columns');\n return;\n }\n grok.shell.warning('No raw intensity columns found for VSN — using quantile normalization');\n quantileNormalize(df, colNames);\n return;\n }\n\n // Build clean DataFrame with simple column names (s1, s2, ...)\n const exprDf = DG.DataFrame.create(df.rowCount);\n for (let i = 0; i < rawColNames.length; i++) {\n const src = df.col(rawColNames[i])!;\n const srcRaw = src.getRawData() as Float32Array | Float64Array;\n const dst = exprDf.columns.addNewFloat(`s${i + 1}`);\n dst.init((r) => srcRaw[r]);\n }\n\n const result: DG.DataFrame = await grok.functions.call('Proteomics:VsnNormalize', {exprDf});\n\n // Copy VSN output (glog2 scale) into log2 intensity columns\n for (let i = 0; i < log2ColNames.length; i++) {\n const dst = df.col(log2ColNames[i])!;\n const src = result.col(`s${i + 1}`)!;\n const dstRaw = dst.getRawData() as Float32Array | Float64Array;\n const srcRaw = src.getRawData() as Float32Array | Float64Array;\n for (let r = 0; r < df.rowCount; r++) {\n if (srcRaw[r] !== DG.FLOAT_NULL)\n dstRaw[r] = srcRaw[r];\n }\n }\n\n df.fireValuesChanged();\n df.setTag('proteomics.normalized', 'true');\n } catch (e: any) {\n console.warn('VSN normalization failed, using quantile fallback:', e);\n if (colNames.length < 2) {\n grok.shell.warning('VSN failed and quantile fallback needs at least 2 columns — data left unnormalized');\n return;\n }\n grok.shell.warning('R environment unavailable — using quantile normalization');\n quantileNormalize(df, colNames);\n }\n}\n\n/** Shows a dialog for normalizing intensity columns.\n * Supports Median Centering, Quantile, and VSN methods with reactive box plot preview.\n * Displays an inline warning when Spectronaut pre-normalized data is detected. */\nexport function showNormalizationDialog(df: DG.DataFrame): void {\n if (df.getTag('proteomics.normalized') === 'true') {\n grok.shell.warning('Data already normalized');\n return;\n }\n\n const log2ColNames = df.columns.toList()\n .filter((c) => c.semType === SEMTYPE.INTENSITY && c.name.startsWith('log2('))\n .map((c) => c.name);\n\n const log2Cols = log2ColNames.map((n) => df.col(n)!);\n\n // Pre-normalized warning banner (NORM-04)\n const warningDiv = ui.div([], {style: {\n background: '#FFF3CD', border: '1px solid #FFEEBA', color: '#856404',\n padding: '8px', margin: '4px 0', borderRadius: '4px',\n display: df.getTag('proteomics.preNormalized') === 'true' ? '' : 'none',\n }});\n warningDiv.textContent =\n 'This data may be pre-normalized (Spectronaut). Additional normalization may distort results.';\n\n // Method selector (NORM-03)\n const methodInput = ui.input.choice('Method', {\n value: 'Median Centering',\n items: ['Median Centering', 'Quantile', 'VSN'],\n nullable: false,\n });\n\n // Column picker\n const colsInput = ui.input.columns('Intensity columns', {\n table: df, available: log2ColNames, value: log2Cols,\n });\n\n // Box plot preview container\n const plotContainer = ui.div([], {style: {\n width: '100%', height: '250px', border: '1px solid #ddd', marginTop: '8px',\n }});\n\n function updatePreview(): void {\n plotContainer.innerHTML = '';\n const selected = colsInput.value.map((c: DG.Column) => c.name);\n if (selected.length === 0) return;\n\n // Clone DataFrame and apply selected normalization for preview\n const clone = df.clone(null, selected);\n const method = methodInput.value;\n if (method === 'Median Centering')\n medianNormalize(clone, selected);\n else if (method === 'Quantile')\n quantileNormalize(clone, selected);\n // VSN requires async R call -- show un-normalized distributions as preview\n\n const longDf = unpivotIntensities(clone, selected);\n const boxPlot = DG.Viewer.boxPlot(longDf, {\n valueColumnName: 'Intensity', categoryColumnName: 'Sample',\n } as any);\n boxPlot.root.style.width = '100%';\n boxPlot.root.style.height = '220px';\n plotContainer.appendChild(boxPlot.root);\n }\n\n methodInput.onChanged.subscribe(() => updatePreview());\n colsInput.onChanged.subscribe(() => updatePreview());\n updatePreview();\n\n ui.dialog('Normalize')\n .add(warningDiv)\n .add(methodInput)\n .add(colsInput)\n .add(plotContainer)\n .onOK(async () => {\n const selected = colsInput.value.map((c: DG.Column) => c.name);\n const method = methodInput.value as string;\n if (method === 'Median Centering')\n medianNormalize(df, selected);\n else if (method === 'Quantile')\n quantileNormalize(df, selected);\n else if (method === 'VSN')\n await vsnNormalize(df, selected);\n grok.shell.info(`Normalized ${selected.length} columns (${method})`);\n })\n .show();\n}\n","/**\n * Phase 16 SPC AppData I/O layer.\n *\n * Sole owner of `System:AppData/Proteomics/spc/runs.csv`,\n * `runs-meta.json`, and `baseline-<slug>.json`. The math layer in\n * `./spc.ts` stays AppData-free; the dashboard in `viewers/spc-dashboard.ts`\n * stays I/O-free. This module is the only file in the package that touches\n * the SPC AppData paths.\n *\n * ## Phase 17 additivity contract (CONTEXT.md D-02)\n *\n * Phase 17 reads runs.csv with the SAME 13-column shape and appends a\n * `campaign_id` column when saving a run into a campaign. Existing rows\n * back-fill with NULL — no migration script. The Phase 16 dashboard ignores\n * `campaign_id` if present so a v1.4 reader stays compatible with v1.5\n * writers.\n *\n * ## Concurrency\n *\n * Single-writer assumption per CONTEXT.md D-02. No file lock. A second\n * concurrent appendRun would silently overwrite — the expected single-user\n * usage pattern (one Datagrok user per machine) makes this acceptable for v1.4.\n *\n * ## Test root override\n *\n * Every public function accepts an optional `{root}` parameter pointing at\n * an alternate `System:AppData/Proteomics/spc-test/<uuid>` sandbox for tests\n * — production code never passes `root`, so the default `RUNS_DIR_DEFAULT`\n * is used.\n */\nimport * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {BaselineSnapshot, SpcRulesEnabled, SpcMetrics, MetricBaseline} from './spc';\n\nexport type {BaselineSnapshot, SpcRulesEnabled, SpcMetrics, MetricBaseline};\n\nexport const RUNS_DIR_DEFAULT = 'System:AppData/Proteomics/spc';\nexport const RUNS_CSV_PATH = 'System:AppData/Proteomics/spc/runs.csv';\nexport const RUNS_META_PATH = 'System:AppData/Proteomics/spc/runs-meta.json';\nexport const RUNS_CSV_SCHEMA_VERSION = '1';\n\nexport const RUNS_CSV_COLUMNS: readonly string[] = [\n 'run_id',\n 'instrument_id',\n 'acquisition_datetime',\n 'run_label',\n 'median_intensity',\n 'missing_pct',\n 'control_corr',\n 'protein_count',\n 'status',\n 'rules_tripped',\n 'source_project_id',\n 'source_df_name',\n 'computed_at',\n];\n\nexport interface SpcRunRow {\n run_id: string;\n instrument_id: string;\n acquisition_datetime: string;\n run_label: string;\n median_intensity: number;\n missing_pct: number;\n control_corr: number;\n protein_count: number;\n status: 'pass' | 'flagged' | 'out_of_control';\n rules_tripped: string[];\n source_project_id: string | null;\n source_df_name: string;\n computed_at: string;\n}\n\nexport interface IterationTraceEntry {\n iter: number;\n dropped: string[];\n}\n\nexport interface LockedBaseline {\n instrument_id: string;\n locked_at: string;\n included_run_ids: string[];\n excluded_run_ids: string[];\n iteration_trace: IterationTraceEntry[];\n metrics: BaselineSnapshot;\n rules_enabled: SpcRulesEnabled;\n}\n\nexport interface StorageOpts {\n /** Override the AppData root (used by tests; production callers omit). */\n root?: string;\n}\n\nconst SCHEMA_VERSION_KEY = 'spc.runs.schema_version';\n\nfunction root(opts?: StorageOpts): string {\n return (opts && opts.root) ? opts.root : RUNS_DIR_DEFAULT;\n}\n\nfunction runsCsvPath(opts?: StorageOpts): string {\n return `${root(opts)}/runs.csv`;\n}\n\nfunction runsMetaPath(opts?: StorageOpts): string {\n return `${root(opts)}/runs-meta.json`;\n}\n\nfunction baselinePath(instrumentId: string, opts?: StorageOpts): string {\n return `${root(opts)}/baseline-${slugifyInstrumentId(instrumentId)}.json`;\n}\n\n// =====================================================================================\n// Slugify — T-16-01 mitigation. Mirrors publishing/publish-state.ts:slugifyTarget but\n// PRESERVES case so instrument names like 'QExactive-01' round-trip exactly.\n// =====================================================================================\n\nexport function slugifyInstrumentId(raw: string): string {\n if (raw == null) return 'unnamed';\n let s = String(raw)\n .replace(/[^A-Za-z0-9._-]+/g, '-')\n .replace(/-{2,}/g, '-')\n .replace(/^[-.]+|[-.]+$/g, '')\n .slice(0, 64)\n .replace(/[-.]+$/g, '');\n if (s.length === 0) s = 'unnamed';\n return s;\n}\n\n// =====================================================================================\n// CSV helpers — small and explicit so the upsert-by-key pattern stays simple.\n// DG.DataFrame.fromObjects + toCsv is avoided because it muddies number↔string\n// type inference on the round-trip.\n// =====================================================================================\n\nfunction csvEscape(value: string): string {\n if (value.indexOf(',') < 0 && value.indexOf('\"') < 0 && value.indexOf('\\n') < 0)\n return value;\n return '\"' + value.replace(/\"/g, '\"\"') + '\"';\n}\n\nfunction parseCsvRow(line: string): string[] {\n const out: string[] = [];\n let i = 0;\n while (i < line.length) {\n if (line[i] === '\"') {\n i++;\n let cell = '';\n while (i < line.length) {\n if (line[i] === '\"') {\n if (line[i + 1] === '\"') { cell += '\"'; i += 2; }\n else { i++; break; }\n } else { cell += line[i]; i++; }\n }\n out.push(cell);\n if (line[i] === ',') i++;\n } else {\n let cell = '';\n while (i < line.length && line[i] !== ',') { cell += line[i]; i++; }\n out.push(cell);\n if (line[i] === ',') i++;\n }\n }\n return out;\n}\n\nfunction parseCsv(text: string): string[][] {\n const rows: string[][] = [];\n // Strip trailing newline; rows separated by \\n. CSV cells may include \\n if\n // they're quoted, but the SPC schema never carries embedded newlines.\n const lines = text.split('\\n').filter((l) => l.length > 0);\n for (const line of lines) rows.push(parseCsvRow(line));\n return rows;\n}\n\nfunction serializeRow(row: SpcRunRow): string {\n const ordered = [\n row.run_id,\n row.instrument_id,\n row.acquisition_datetime,\n row.run_label,\n String(row.median_intensity),\n String(row.missing_pct),\n String(row.control_corr),\n String(row.protein_count),\n row.status,\n JSON.stringify(row.rules_tripped),\n row.source_project_id == null ? '' : row.source_project_id,\n row.source_df_name,\n row.computed_at,\n ];\n return ordered.map(csvEscape).join(',');\n}\n\nfunction deserializeRow(cells: string[]): SpcRunRow {\n const idx = (n: string) => RUNS_CSV_COLUMNS.indexOf(n);\n const get = (n: string) => cells[idx(n)] ?? '';\n let rulesTripped: string[] = [];\n try {\n const raw = get('rules_tripped');\n if (raw) rulesTripped = JSON.parse(raw) as string[];\n } catch { /* malformed → empty */ }\n const sourceProjectId = get('source_project_id');\n return {\n run_id: get('run_id'),\n instrument_id: get('instrument_id'),\n acquisition_datetime: get('acquisition_datetime'),\n run_label: get('run_label'),\n median_intensity: Number(get('median_intensity')),\n missing_pct: Number(get('missing_pct')),\n control_corr: Number(get('control_corr')),\n protein_count: Number(get('protein_count')),\n status: get('status') as SpcRunRow['status'],\n rules_tripped: rulesTripped,\n source_project_id: sourceProjectId.length === 0 ? null : sourceProjectId,\n source_df_name: get('source_df_name'),\n computed_at: get('computed_at'),\n };\n}\n\nfunction emptyCsv(): string {\n return RUNS_CSV_COLUMNS.map(csvEscape).join(',') + '\\n';\n}\n\nfunction rowsToCsv(rows: SpcRunRow[]): string {\n const lines = [RUNS_CSV_COLUMNS.map(csvEscape).join(',')];\n for (const r of rows) lines.push(serializeRow(r));\n return lines.join('\\n') + '\\n';\n}\n\nasync function readRowsFromCsv(opts?: StorageOpts): Promise<SpcRunRow[]> {\n const path = runsCsvPath(opts);\n if (!await grok.dapi.files.exists(path)) return [];\n const text = await grok.dapi.files.readAsText(path);\n const parsed = parseCsv(text);\n if (parsed.length <= 1) return [];\n // First row is the header. Skip it.\n return parsed.slice(1).map(deserializeRow);\n}\n\n// =====================================================================================\n// Schema versioning\n// =====================================================================================\n\nexport async function readRunsMeta(opts?: StorageOpts): Promise<Record<string, string>> {\n const path = runsMetaPath(opts);\n if (!await grok.dapi.files.exists(path)) return {};\n try {\n return JSON.parse(await grok.dapi.files.readAsText(path)) as Record<string, string>;\n } catch (err) {\n // Storage layer is shell-free; user-facing warnings live in the viewer.\n // eslint-disable-next-line no-console\n console.warn(`[spc-storage] failed to parse ${path}: ${err}`);\n return {};\n }\n}\n\nexport async function writeRunsMeta(\n meta: Record<string, string>, opts?: StorageOpts,\n): Promise<void> {\n await grok.dapi.files.writeAsText(runsMetaPath(opts), JSON.stringify(meta, null, 2));\n}\n\nexport async function readSchemaVersion(opts?: StorageOpts): Promise<string | null> {\n const meta = await readRunsMeta(opts);\n return meta[SCHEMA_VERSION_KEY] ?? null;\n}\n\nexport async function writeSchemaVersion(version: string, opts?: StorageOpts): Promise<void> {\n const meta = await readRunsMeta(opts);\n meta[SCHEMA_VERSION_KEY] = version;\n await writeRunsMeta(meta, opts);\n}\n\n// =====================================================================================\n// runs.csv upsert (primary write path)\n// =====================================================================================\n\nfunction genRunId(): string {\n if (typeof crypto !== 'undefined' && (crypto as any).randomUUID)\n return (crypto as any).randomUUID();\n // Fallback for environments without crypto.randomUUID.\n return 'r-' + Math.random().toString(16).slice(2) + '-' + Date.now().toString(16);\n}\n\nexport interface UpsertInput {\n run_id?: string;\n instrument_id: string;\n acquisition_datetime: string;\n run_label: string;\n median_intensity: number;\n missing_pct: number;\n control_corr: number;\n protein_count: number;\n status: SpcRunRow['status'];\n rules_tripped: string[];\n source_project_id: string | null;\n source_df_name: string;\n computed_at: string;\n}\n\n/**\n * Upserts on the composite key (instrument_id, acquisition_datetime). Second\n * invocation with the same key OVERWRITES the prior row (preserving its\n * run_id). First-ever invocation creates runs.csv and pins the schema\n * version in runs-meta.json.\n */\nexport async function upsertRun(\n input: UpsertInput, opts?: StorageOpts,\n): Promise<SpcRunRow> {\n const rows = await readRowsFromCsv(opts);\n const idx = rows.findIndex(\n (r) => r.instrument_id === input.instrument_id &&\n r.acquisition_datetime === input.acquisition_datetime,\n );\n let persisted: SpcRunRow;\n if (idx >= 0) {\n // Preserve the existing run_id on overwrite.\n persisted = {\n ...rows[idx],\n ...input,\n run_id: rows[idx].run_id,\n rules_tripped: input.rules_tripped,\n source_project_id: input.source_project_id,\n } as SpcRunRow;\n rows[idx] = persisted;\n } else {\n persisted = {\n run_id: input.run_id ?? genRunId(),\n instrument_id: input.instrument_id,\n acquisition_datetime: input.acquisition_datetime,\n run_label: input.run_label,\n median_intensity: input.median_intensity,\n missing_pct: input.missing_pct,\n control_corr: input.control_corr,\n protein_count: input.protein_count,\n status: input.status,\n rules_tripped: input.rules_tripped,\n source_project_id: input.source_project_id,\n source_df_name: input.source_df_name,\n computed_at: input.computed_at,\n };\n rows.push(persisted);\n }\n await grok.dapi.files.writeAsText(runsCsvPath(opts), rowsToCsv(rows));\n // First-ever write: pin the schema version. Idempotent on subsequent calls\n // because writeSchemaVersion merges into existing runs-meta.json.\n const version = await readSchemaVersion(opts);\n if (version !== RUNS_CSV_SCHEMA_VERSION)\n await writeSchemaVersion(RUNS_CSV_SCHEMA_VERSION, opts);\n return persisted;\n}\n\n/** Alias for Plan 16-05's wireup, which calls `appendRun` per the plan contract. */\nexport const appendRun = upsertRun;\n\n// =====================================================================================\n// runs.csv read (with optional instrument filter; always sorted by acquisition_datetime ASC)\n// =====================================================================================\n\nexport async function loadRuns(\n instrumentId?: string, opts?: StorageOpts,\n): Promise<SpcRunRow[]> {\n const rows = await readRowsFromCsv(opts);\n const filtered = instrumentId\n ? rows.filter((r) => r.instrument_id === instrumentId)\n : rows;\n // Pitfall 7 lever: ALWAYS sort by acquisition_datetime, never by computed_at\n // or insertion order. ISO-8601 lex-sorts correctly.\n filtered.sort((a, b) => a.acquisition_datetime.localeCompare(b.acquisition_datetime));\n return filtered;\n}\n\n// =====================================================================================\n// Per-instrument baseline JSON\n// =====================================================================================\n\nexport async function loadBaseline(\n instrumentId: string, opts?: StorageOpts,\n): Promise<LockedBaseline | null> {\n const path = baselinePath(instrumentId, opts);\n if (!await grok.dapi.files.exists(path)) return null;\n try {\n return JSON.parse(await grok.dapi.files.readAsText(path)) as LockedBaseline;\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(`[spc-storage] failed to parse baseline at ${path}: ${err}`);\n return null;\n }\n}\n\nexport async function saveBaseline(\n instrumentId: string, baseline: LockedBaseline, opts?: StorageOpts,\n): Promise<void> {\n await grok.dapi.files.writeAsText(\n baselinePath(instrumentId, opts),\n JSON.stringify(baseline, null, 2),\n );\n}\n\n// =====================================================================================\n// Iterative outlier removal (Pitfall 6 lever, capped at 2 iterations).\n// =====================================================================================\n\nconst MAX_BASELINE_ITERATIONS = 2;\n\nfunction meanSdValues(values: number[]): {mean: number; sd: number} {\n const n = values.length;\n if (n === 0) return {mean: NaN, sd: NaN};\n let sum = 0;\n for (const v of values) sum += v;\n const mean = sum / n;\n let sse = 0;\n for (const v of values) {\n const d = v - mean;\n sse += d * d;\n }\n // Sample SD (n-1 denominator) for Shewhart 3σ consistency.\n const sd = n > 1 ? Math.sqrt(sse / (n - 1)) : 0;\n return {mean, sd};\n}\n\nexport function iterativeOutlierRemoval(\n series: Array<{run_id: string; value: number}>,\n maxIter: number = MAX_BASELINE_ITERATIONS,\n): {\n retained_run_ids: string[];\n excluded_run_ids: string[];\n iteration_trace: IterationTraceEntry[];\n} {\n const retained = series.slice();\n const excluded: Array<{run_id: string; value: number}> = [];\n const trace: IterationTraceEntry[] = [];\n\n if (retained.length < 3) {\n return {\n retained_run_ids: retained.map((s) => s.run_id),\n excluded_run_ids: [],\n iteration_trace: [],\n };\n }\n\n for (let iter = 1; iter <= maxIter; iter++) {\n const vals = retained.map((s) => s.value).filter((v) => Number.isFinite(v));\n const {mean, sd} = meanSdValues(vals);\n if (!Number.isFinite(sd) || sd === 0) break;\n const dropped: typeof retained = [];\n for (let i = retained.length - 1; i >= 0; i--) {\n const v = retained[i].value;\n if (!Number.isFinite(v)) continue;\n const z = (v - mean) / sd;\n if (Math.abs(z) > 3) {\n dropped.push(retained[i]);\n excluded.push(retained[i]);\n retained.splice(i, 1);\n }\n }\n if (dropped.length === 0) break;\n trace.push({iter, dropped: dropped.map((d) => d.run_id)});\n }\n\n return {\n retained_run_ids: retained.map((s) => s.run_id),\n excluded_run_ids: excluded.map((s) => s.run_id),\n iteration_trace: trace,\n };\n}\n\n// =====================================================================================\n// Baseline statistics (mean+sd per metric over retained rows)\n// =====================================================================================\n\nconst METRIC_KEYS: Array<keyof BaselineSnapshot> = [\n 'median_intensity', 'missing_pct', 'control_corr', 'protein_count',\n];\n\nfunction metricBaseline(values: number[]): MetricBaseline {\n const clean = values.filter((v) => Number.isFinite(v));\n if (clean.length < 2) return {mean: NaN, sd: NaN};\n const {mean, sd} = meanSdValues(clean);\n return {mean, sd};\n}\n\nexport function computeBaselineStats(retainedRows: SpcRunRow[]): BaselineSnapshot {\n const snapshot = {} as BaselineSnapshot;\n for (const m of METRIC_KEYS)\n snapshot[m] = metricBaseline(retainedRows.map((r) => r[m] as number));\n return snapshot;\n}\n\n// =====================================================================================\n// Reuse a DG.DataFrame helper for downstream viewers — small but keeps the dashboard\n// from re-implementing the CSV walk. Plan 16-06 calls this in createSpcChartPanel.\n// =====================================================================================\n\nexport function runsToDataFrame(rows: SpcRunRow[]): DG.DataFrame {\n const get = <T>(fn: (r: SpcRunRow) => T) => rows.map(fn);\n const cols = [\n DG.Column.fromStrings('run_id', get((r) => r.run_id)),\n DG.Column.fromStrings('instrument_id', get((r) => r.instrument_id)),\n DG.Column.fromList(DG.COLUMN_TYPE.DATE_TIME, 'acquisition_datetime',\n get((r) => Date.parse(r.acquisition_datetime))),\n DG.Column.fromStrings('run_label', get((r) => r.run_label)),\n DG.Column.fromFloat32Array('median_intensity', new Float32Array(get((r) => r.median_intensity))),\n DG.Column.fromFloat32Array('missing_pct', new Float32Array(get((r) => r.missing_pct))),\n DG.Column.fromFloat32Array('control_corr', new Float32Array(get((r) => r.control_corr))),\n DG.Column.fromFloat32Array('protein_count', new Float32Array(get((r) => r.protein_count))),\n DG.Column.fromStrings('status', get((r) => r.status)),\n DG.Column.fromStrings('rules_tripped', get((r) => JSON.stringify(r.rules_tripped))),\n DG.Column.fromStrings('source_project_id', get((r) => r.source_project_id ?? '')),\n DG.Column.fromStrings('source_df_name', get((r) => r.source_df_name)),\n DG.Column.fromStrings('computed_at', get((r) => r.computed_at)),\n ];\n return DG.DataFrame.fromColumns(cols);\n}\n","/**\n * Phase 16 SPC math + tag helpers.\n *\n * Pure TS layer — zero shell / UI side effects. AppData I/O lives in\n * `src/analysis/spc-storage.ts` (Plan 16-03); viewers live in\n * `src/viewers/spc-dashboard.ts` (Plan 16-06). Public-domain math: Nelson 1984\n * for the eight rules and Wheeler 1992 for the n=2 MR-chart constants.\n *\n * Belt-and-braces (Phase 15 D-05): {@link setSpcStatus} persists a single-row\n * string column `~spc_metrics_meta` carrying `JSON.stringify(metrics)`. One\n * column keeps the published-project allowlist small and survives the\n * serializer-strip pattern that loses df tags.\n */\nimport * as DG from 'datagrok-api/dg';\n\nimport {GroupAssignment} from './experiment-setup';\n\n/** Run-identity payload persisted in `proteomics.spc_run_meta` JSON tag. */\nexport interface RunMeta {\n instrument_id: string;\n acquisition_datetime: string;\n}\n\n/** Per-run rollup written to AppData runs.csv and surfaced on every analyzed df. */\nexport interface SpcMetrics {\n median_intensity: number;\n missing_pct: number;\n control_corr: number;\n protein_count: number;\n sample_count: number;\n computed_at: string;\n}\n\nexport type SpcStatus = 'pass' | 'flagged' | 'out_of_control';\n\n/** One run's evaluated rules, with status classification per D-04. */\nexport interface SpcRuleResult {\n status: SpcStatus;\n rulesTripped: string[];\n}\n\nexport type NelsonRuleId = 'nelson_1' | 'nelson_2' | 'nelson_3' | 'nelson_4'\n | 'nelson_5' | 'nelson_6' | 'nelson_7' | 'nelson_8';\n\n/** Per-metric enabled flags (used by the simple form of evaluateNelsonRules). */\nexport type FlatRulesEnabled = Record<NelsonRuleId, boolean>;\n\n/** Four-metric rules-enabled grid persisted in baseline-<instrument_id>.json. */\nexport interface SpcRulesEnabled {\n median_intensity: FlatRulesEnabled;\n missing_pct: FlatRulesEnabled;\n control_corr: FlatRulesEnabled;\n protein_count: FlatRulesEnabled;\n}\n\n/** Mean + standard deviation for one metric over a locked baseline window. */\nexport interface MetricBaseline {\n mean: number;\n sd: number;\n}\n\n/** Four-metric baseline snapshot stored on baseline-<instrument_id>.json. */\nexport interface BaselineSnapshot {\n median_intensity: MetricBaseline;\n missing_pct: MetricBaseline;\n control_corr: MetricBaseline;\n protein_count: MetricBaseline;\n}\n\n/** Result of iteratively pruning 3σ outliers from a baseline window. */\nexport interface IterativeBaselineResult {\n mean: number;\n sd: number;\n includedCount: number;\n excludedIndices: number[];\n iterationTrace: Array<{iter: number; dropped: number[]}>;\n}\n\n/** Wheeler 1992 control-chart constants for n=2 (used by Plan 16-06 MR-chart). */\nexport const WHEELER_D2 = 1.128;\nexport const WHEELER_D4 = 3.267;\n\n/** Phase 16 explicit ban (Pitfall 5) — Spectronaut Candidates carry pre-computed DE\n * with no per-sample intensities, so SPC cannot be computed from them. */\nconst SPECTRONAUT_CANDIDATES_REFUSAL =\n 'SPC requires per-sample intensities. Re-import this analysis from the Spectronaut PG ' +\n 'report (not the Candidates report) to compute SPC.';\n\nconst BELT_AND_BRACES_COLUMN = '~spc_metrics_meta';\n\n// =====================================================================================\n// Run-meta tag helpers (mirror setGroups/getGroups in experiment-setup.ts).\n// =====================================================================================\n\nexport function setRunMeta(df: DG.DataFrame, meta: RunMeta): void {\n df.setTag('proteomics.spc_run_meta', JSON.stringify(meta));\n}\n\nexport function getRunMeta(df: DG.DataFrame): RunMeta | null {\n const raw = df.getTag('proteomics.spc_run_meta');\n if (!raw) return null;\n try {\n return JSON.parse(raw) as RunMeta;\n } catch {\n return null;\n }\n}\n\n// =====================================================================================\n// Source-gate (Pitfall 5 — Spectronaut Candidates hard refusal).\n// =====================================================================================\n\nexport function assertSpcEligible(df: DG.DataFrame): void {\n const source = df.getTag('proteomics.source');\n if (source === 'spectronaut-candidates')\n throw new Error(SPECTRONAUT_CANDIDATES_REFUSAL);\n}\n\n// =====================================================================================\n// Metric math (NaN-tolerant; matches qc-computations.ts semantics).\n// =====================================================================================\n\nfunction isMissing(col: DG.Column, i: number): boolean {\n if (col.isNone(i)) return true;\n const v = col.get(i);\n if (typeof v === 'number' && Number.isNaN(v)) return true;\n return false;\n}\n\nfunction median(values: number[]): number {\n if (values.length === 0) return NaN;\n const sorted = values.slice().sort((a, b) => a - b);\n const n = sorted.length;\n const mid = Math.floor(n / 2);\n return (n % 2 === 0) ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];\n}\n\nfunction pearson(xs: number[], ys: number[]): number {\n const n = xs.length;\n if (n < 3) return NaN;\n let sumX = 0, sumY = 0;\n for (let i = 0; i < n; i++) { sumX += xs[i]; sumY += ys[i]; }\n const mx = sumX / n;\n const my = sumY / n;\n let num = 0, dx2 = 0, dy2 = 0;\n for (let i = 0; i < n; i++) {\n const dx = xs[i] - mx;\n const dy = ys[i] - my;\n num += dx * dy;\n dx2 += dx * dx;\n dy2 += dy * dy;\n }\n const denom = Math.sqrt(dx2 * dy2);\n return denom === 0 ? NaN : num / denom;\n}\n\nfunction resolveCols(df: DG.DataFrame, names: string[]): DG.Column[] {\n const out: DG.Column[] = [];\n for (const name of names) {\n const c = df.col(name);\n if (c !== null) out.push(c);\n }\n return out;\n}\n\nexport function computeSpcMetrics(\n df: DG.DataFrame, groups: GroupAssignment, runMeta: RunMeta,\n): SpcMetrics {\n // Use runMeta so a future refactor can persist it alongside the metrics\n // without breaking the public signature; intentionally not stored here.\n void runMeta;\n\n const g1Cols = resolveCols(df, groups.group1.columns);\n const g2Cols = resolveCols(df, groups.group2.columns);\n const intensityCols = g1Cols.concat(g2Cols);\n const sampleCount = groups.group1.columns.length + groups.group2.columns.length;\n\n // Median: flat array of all non-null intensity cells.\n const allValues: number[] = [];\n const rowCount = df.rowCount;\n let missingCells = 0;\n let totalCells = 0;\n let rowsWithData = 0;\n for (let r = 0; r < rowCount; r++) {\n let rowHasData = false;\n for (const col of intensityCols) {\n totalCells++;\n if (isMissing(col, r)) {\n missingCells++;\n } else {\n allValues.push(col.get(r) as number);\n rowHasData = true;\n }\n }\n if (rowHasData) rowsWithData++;\n }\n\n const medianIntensity = median(allValues);\n const missingPct = totalCells === 0 ? NaN : (missingCells / totalCells) * 100;\n\n // Pairwise Pearson over Group 1 controls.\n let controlCorr = NaN;\n if (g1Cols.length >= 2) {\n let sum = 0;\n let pairCount = 0;\n for (let i = 0; i < g1Cols.length; i++) {\n for (let j = i + 1; j < g1Cols.length; j++) {\n const ci = g1Cols[i];\n const cj = g1Cols[j];\n const xs: number[] = [];\n const ys: number[] = [];\n for (let r = 0; r < rowCount; r++) {\n if (!isMissing(ci, r) && !isMissing(cj, r)) {\n xs.push(ci.get(r) as number);\n ys.push(cj.get(r) as number);\n }\n }\n const r = pearson(xs, ys);\n if (!Number.isNaN(r)) {\n sum += r;\n pairCount++;\n }\n }\n }\n controlCorr = pairCount === 0 ? NaN : sum / pairCount;\n }\n\n return {\n median_intensity: medianIntensity,\n missing_pct: missingPct,\n control_corr: controlCorr,\n protein_count: rowsWithData,\n sample_count: sampleCount,\n computed_at: new Date().toISOString(),\n };\n}\n\n// =====================================================================================\n// Nelson rules engine (1984 definitions, locked in CONTEXT.md canonical_refs).\n// =====================================================================================\n\nexport function defaultRulesEnabled(): FlatRulesEnabled {\n return {\n nelson_1: true, nelson_2: false, nelson_3: false, nelson_4: false,\n nelson_5: true, nelson_6: false, nelson_7: false, nelson_8: false,\n };\n}\n\nexport function defaultRulesEnabledAllMetrics(): SpcRulesEnabled {\n const d = defaultRulesEnabled();\n return {\n median_intensity: {...d}, missing_pct: {...d},\n control_corr: {...d}, protein_count: {...d},\n };\n}\n\ninterface RuleTripContext {\n series: number[];\n z: number[];\n mean: number;\n sd: number;\n}\n\nfunction rule1(ctx: RuleTripContext): boolean {\n // Single point > 3σ. Evaluated at the tail.\n const i = ctx.z.length - 1;\n return Math.abs(ctx.z[i]) > 3;\n}\n\nfunction rule2(ctx: RuleTripContext): boolean {\n // 9 consecutive points on the same side of CL.\n if (ctx.series.length < 9) return false;\n const tail = ctx.series.slice(-9);\n const above = tail.every((v) => v > ctx.mean);\n const below = tail.every((v) => v < ctx.mean);\n return above || below;\n}\n\nfunction rule3(ctx: RuleTripContext): boolean {\n // 6 consecutive points steadily increasing or decreasing.\n if (ctx.series.length < 6) return false;\n const t = ctx.series.slice(-6);\n let inc = true, dec = true;\n for (let i = 1; i < 6; i++) {\n if (!(t[i] > t[i - 1])) inc = false;\n if (!(t[i] < t[i - 1])) dec = false;\n }\n return inc || dec;\n}\n\nfunction rule4(ctx: RuleTripContext): boolean {\n // 14 consecutive points alternating above/below CL.\n if (ctx.series.length < 14) return false;\n const t = ctx.series.slice(-14);\n const sides = t.map((v) => v > ctx.mean ? 1 : (v < ctx.mean ? -1 : 0));\n for (let i = 1; i < sides.length; i++) {\n if (sides[i] === 0 || sides[i - 1] === 0) return false;\n if (sides[i] === sides[i - 1]) return false;\n }\n return true;\n}\n\nfunction rule5(ctx: RuleTripContext): boolean {\n // 2-of-3 consecutive points beyond 2σ on the same side. Evaluated at the tail.\n if (ctx.z.length < 3) {\n // With fewer than 3 points, count current + prior(s).\n const z = ctx.z;\n if (z.length < 2) return false;\n const above2 = z.filter((v) => v > 2).length;\n const below2 = z.filter((v) => v < -2).length;\n return above2 >= 2 || below2 >= 2;\n }\n const last3 = ctx.z.slice(-3);\n const above = last3.filter((v) => v > 2).length;\n const below = last3.filter((v) => v < -2).length;\n return above >= 2 || below >= 2;\n}\n\nfunction rule6(ctx: RuleTripContext): boolean {\n // 4-of-5 consecutive points beyond 1σ on the same side.\n if (ctx.z.length < 5) return false;\n const last5 = ctx.z.slice(-5);\n const above = last5.filter((v) => v > 1).length;\n const below = last5.filter((v) => v < -1).length;\n return above >= 4 || below >= 4;\n}\n\nfunction rule7(ctx: RuleTripContext): boolean {\n // 15 consecutive points within 1σ of CL.\n if (ctx.z.length < 15) return false;\n return ctx.z.slice(-15).every((v) => Math.abs(v) < 1);\n}\n\nfunction rule8(ctx: RuleTripContext): boolean {\n // 8 consecutive points outside 1σ on either side.\n if (ctx.z.length < 8) return false;\n return ctx.z.slice(-8).every((v) => Math.abs(v) > 1);\n}\n\nconst RULE_FNS: Record<NelsonRuleId, (ctx: RuleTripContext) => boolean> = {\n nelson_1: rule1, nelson_2: rule2, nelson_3: rule3, nelson_4: rule4,\n nelson_5: rule5, nelson_6: rule6, nelson_7: rule7, nelson_8: rule8,\n};\n\nconst RULE_IDS: NelsonRuleId[] = [\n 'nelson_1', 'nelson_2', 'nelson_3', 'nelson_4',\n 'nelson_5', 'nelson_6', 'nelson_7', 'nelson_8',\n];\n\n/**\n * Simple form — evaluates the enabled Nelson rules on a single metric's series.\n * `enabled` is a flat record (no per-metric grid). For the aggregate form used by\n * the dashboard layer, see {@link evaluateNelsonRulesAllMetrics}.\n */\nexport function evaluateNelsonRules(\n series: number[],\n baselineMean: number,\n baselineSd: number,\n enabled: FlatRulesEnabled,\n metricLabel?: string,\n): SpcRuleResult {\n if (series.length === 0 || !Number.isFinite(baselineSd) || baselineSd === 0)\n return {status: 'pass', rulesTripped: []};\n const z = series.map((v) => (v - baselineMean) / baselineSd);\n const ctx: RuleTripContext = {series, z, mean: baselineMean, sd: baselineSd};\n const rulesTripped: string[] = [];\n for (const id of RULE_IDS) {\n if (!enabled[id]) continue;\n if (RULE_FNS[id](ctx))\n rulesTripped.push(metricLabel ? `${id}@${metricLabel}` : id);\n }\n return {status: classifyStatus(rulesTripped), rulesTripped};\n}\n\n/**\n * Aggregate form — evaluates rules across all four metrics. Used by the dashboard\n * and storage layers; the simple form above is the test-facing entry point.\n */\nexport function evaluateNelsonRulesAllMetrics(\n newMetrics: SpcMetrics,\n priorSeries: {\n median_intensity: number[]; missing_pct: number[];\n control_corr: number[]; protein_count: number[];\n },\n baseline: BaselineSnapshot,\n enabled: SpcRulesEnabled,\n): SpcRuleResult {\n const tripped: string[] = [];\n const metricNames: Array<keyof BaselineSnapshot> = [\n 'median_intensity', 'missing_pct', 'control_corr', 'protein_count',\n ];\n for (const m of metricNames) {\n const newValue = newMetrics[m];\n if (!Number.isFinite(newValue)) continue; // D-03: NaN metric = unavailable, skip\n const series = priorSeries[m].concat([newValue]);\n const r = evaluateNelsonRules(series, baseline[m].mean, baseline[m].sd, enabled[m], m);\n for (const trip of r.rulesTripped) tripped.push(trip);\n }\n return {status: classifyStatus(tripped), rulesTripped: tripped};\n}\n\nexport function classifyStatus(rulesTripped: string[]): SpcStatus {\n if (rulesTripped.length === 0) return 'pass';\n for (const t of rulesTripped) {\n if (t.startsWith('nelson_1@') || t === 'nelson_1') return 'out_of_control';\n }\n return 'flagged';\n}\n\n// =====================================================================================\n// Iterative baseline (3σ outlier removal, capped at 2 iterations per Pitfall 6).\n// =====================================================================================\n\nfunction meanSd(values: number[]): {mean: number; sd: number} {\n const n = values.length;\n if (n === 0) return {mean: NaN, sd: NaN};\n let sum = 0;\n for (const v of values) sum += v;\n const mean = sum / n;\n let sse = 0;\n for (const v of values) {\n const d = v - mean;\n sse += d * d;\n }\n // Sample standard deviation (n-1) when n>1; population (n) when n=1.\n const sd = n > 1 ? Math.sqrt(sse / (n - 1)) : 0;\n return {mean, sd};\n}\n\nconst MAX_BASELINE_ITERATIONS = 2;\n\nexport function computeIterativeBaseline(\n values: number[], iterateOutliers: boolean,\n): IterativeBaselineResult {\n const includedIdx = new Set<number>();\n for (let i = 0; i < values.length; i++) includedIdx.add(i);\n const iterationTrace: Array<{iter: number; dropped: number[]}> = [];\n let mean = NaN;\n let sd = NaN;\n\n if (!iterateOutliers) {\n ({mean, sd} = meanSd(values));\n return {\n mean, sd, includedCount: values.length, excludedIndices: [], iterationTrace,\n };\n }\n\n for (let iter = 1; iter <= MAX_BASELINE_ITERATIONS; iter++) {\n const current = Array.from(includedIdx).map((i) => values[i]);\n const stats = meanSd(current);\n mean = stats.mean;\n sd = stats.sd;\n if (!Number.isFinite(sd) || sd === 0) break;\n const dropped: number[] = [];\n for (const i of includedIdx) {\n const z = (values[i] - mean) / sd;\n if (Math.abs(z) > 3) dropped.push(i);\n }\n if (dropped.length === 0) break;\n for (const i of dropped) includedIdx.delete(i);\n iterationTrace.push({iter, dropped});\n // Recompute after dropping for the final returned mean/sd.\n const updated = Array.from(includedIdx).map((i) => values[i]);\n ({mean, sd} = meanSd(updated));\n }\n\n const excluded: number[] = [];\n for (let i = 0; i < values.length; i++)\n if (!includedIdx.has(i)) excluded.push(i);\n\n return {\n mean, sd,\n includedCount: includedIdx.size,\n excludedIndices: excluded,\n iterationTrace,\n };\n}\n\n// =====================================================================================\n// Status persistence on the analyzed df (tags + belt-and-braces column).\n// =====================================================================================\n\nfunction ensureFreshStringColumn(df: DG.DataFrame, name: string): DG.Column {\n if (df.columns.contains(name))\n df.columns.remove(name);\n return df.columns.addNewString(name);\n}\n\nexport function setSpcStatus(\n df: DG.DataFrame, metrics: SpcMetrics, ruleResult: SpcRuleResult,\n): void {\n df.setTag('proteomics.spc_metrics', JSON.stringify(metrics));\n df.setTag('proteomics.spc_status', ruleResult.status);\n df.setTag('proteomics.spc_rules_tripped', JSON.stringify(ruleResult.rulesTripped));\n\n // Belt-and-braces (Phase 15 D-05) — single column carries the JSON so a\n // published Project's serializer-strip can be recovered from this column\n // even if df tags don't survive.\n const col = ensureFreshStringColumn(df, BELT_AND_BRACES_COLUMN);\n const payload = JSON.stringify({\n metrics, status: ruleResult.status, rulesTripped: ruleResult.rulesTripped,\n });\n if (df.rowCount === 0) {\n // Empty df has no row to write — the column still pins the schema.\n return;\n }\n col.set(0, payload);\n}\n\nexport function getSpcStatus(df: DG.DataFrame): {\n metrics: SpcMetrics; status: SpcStatus; rulesTripped: string[];\n} | null {\n const metricsRaw = df.getTag('proteomics.spc_metrics');\n const statusRaw = df.getTag('proteomics.spc_status');\n const rulesRaw = df.getTag('proteomics.spc_rules_tripped');\n if (!metricsRaw || !statusRaw) return null;\n try {\n return {\n metrics: JSON.parse(metricsRaw) as SpcMetrics,\n status: statusRaw as SpcStatus,\n rulesTripped: rulesRaw ? (JSON.parse(rulesRaw) as string[]) : [],\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Recovers metrics from the belt-and-braces column when tags are missing\n * (Phase 15 D-05 fallback — protects against the serializer-strip pattern).\n */\nexport function recoverSpcMetricsFromColumn(df: DG.DataFrame): SpcMetrics | null {\n if (!df.columns.contains(BELT_AND_BRACES_COLUMN)) return null;\n const col = df.col(BELT_AND_BRACES_COLUMN);\n if (!col || df.rowCount === 0) return null;\n const raw = col.get(0);\n if (typeof raw !== 'string' || raw.length === 0) return null;\n try {\n const parsed = JSON.parse(raw);\n return parsed && parsed.metrics ? (parsed.metrics as SpcMetrics) : null;\n } catch {\n return null;\n }\n}\n","import * as grok from 'datagrok-api/grok';\n\n/**\n * Shared UniProt subcellular-location service.\n *\n * The classifier, keyword map, and hex palette are ported VERBATIM from the\n * locked CK-omics contract (~/Downloads/ck/CKomics_tool2.py:1384-1436\n * `parse_subcellular_location` / `get_location_colors` and\n * Subcellular_Location_Classification_README.txt). Any divergence is a parity\n * regression — do not re-derive. Pure functions do no I/O.\n */\n\n// --- Verbatim CK-omics 11-category keyword map (dict insertion order matters:\n// it is the tie-break for equal-position matches). ---\n\nexport const LOCATION_KEYWORDS: Record<string, string[]> = {\n 'Nucleus': ['nucleus', 'nuclear', 'nucleoplasm', 'chromatin', 'nucleolus',\n 'nuclear envelope', 'nuclear membrane', 'nuclear pore', 'nuclear speck',\n 'cajal body', 'nuclear body'],\n 'Cytoplasm': ['cytoplasm', 'cytosol', 'cytoplasmic', 'cytoskeleton',\n 'microtubule', 'actin', 'intermediate filament', 'sarcomere', 'myofibril',\n 'z disc', 'z disk', 'spindle', 'centriole', 'centrosome', 'cilium',\n 'flagellum', 'stress fiber'],\n 'Mitochondria': ['mitochondria', 'mitochondrial', 'mitochondrion',\n 'mitochondrial matrix', 'mitochondrial membrane',\n 'mitochondrial inner membrane', 'mitochondrial outer membrane',\n 'mitochondrial intermembrane space'],\n 'ER': ['endoplasmic reticulum', 'sarcoplasmic reticulum',\n 'rough endoplasmic reticulum', 'smooth endoplasmic reticulum',\n 'er-golgi intermediate compartment', 'ergic'],\n 'Golgi': ['golgi', 'trans-golgi', 'golgi apparatus', 'golgi membrane',\n 'cis-golgi', 'trans-golgi network', 'tgn'],\n 'Plasma Membrane': ['plasma membrane', 'cell membrane', 'cell surface',\n 'tight junction', 'gap junction', 'adherens junction', 'desmosome',\n 'focal adhesion', 'cell junction', 'synapse', 'postsynaptic',\n 'presynaptic', 'neuromuscular junction'],\n 'Lysosome': ['lysosome', 'lysosomal', 'vacuole', 'lysosomal membrane',\n 'autophagosome', 'phagosome'],\n 'Peroxisome': ['peroxisome', 'peroxisomal', 'glyoxysome'],\n 'Ribosome': ['ribosome', 'ribosomal', 'ribosomal protein', 'polysome'],\n 'Extracellular': ['extracellular', 'secreted', 'extracellular space',\n 'extracellular matrix', 'basement membrane', 'basal lamina', 'collagen',\n 'ecm'],\n 'Vesicles': ['vesicle', 'endosome', 'transport vesicle', 'secretory vesicle',\n 'early endosome', 'late endosome', 'recycling endosome',\n 'clathrin-coated vesicle', 'coated vesicle'],\n};\n\n/** Locked hex palette (README §COLOR SCHEME) as ARGB ints — same 0xFF… form as\n * volcano.ts:60-62. 11 categories + Unknown. */\nexport const LOCATION_COLORS: Record<string, number> = {\n 'Nucleus': 0xFF000000 | parseInt('FF6B6B', 16),\n 'Cytoplasm': 0xFF000000 | parseInt('ECDC44', 16),\n 'Mitochondria': 0xFF000000 | parseInt('45B7D1', 16),\n 'ER': 0xFF000000 | parseInt('96CEB4', 16),\n 'Golgi': 0xFF000000 | parseInt('FAAFFE', 16),\n 'Plasma Membrane': 0xFF000000 | parseInt('DDA0DD', 16),\n 'Lysosome': 0xFF000000 | parseInt('F39C12', 16),\n 'Peroxisome': 0xFF000000 | parseInt('E17055', 16),\n 'Ribosome': 0xFF000000 | parseInt('A29BFE', 16),\n 'Extracellular': 0xFF000000 | parseInt('FD79A8', 16),\n 'Vesicles': 0xFF000000 | parseInt('FDCB6E', 16),\n 'Unknown': 0xFF000000 | parseInt('CCCCCC', 16),\n};\n\n/** Escapes regex metacharacters (mirrors Python `re.escape` faithfully — the\n * current keywords contain none, but stay defensive). */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** First location keyword (by earliest character position across ALL\n * categories) in the lowercased RAW text. Ties keep the first-iterated\n * category (strict `<`), so keyword-map insertion order is the tie-break.\n * The raw string is NOT pre-stripped (Pitfall 2). */\nfunction findFirstLocation(text: string): string | null {\n if (!text) return null;\n const lower = text.toLowerCase();\n let earliestMatch: string | null = null;\n let earliestPos = Infinity;\n for (const category of Object.keys(LOCATION_KEYWORDS)) {\n for (const keyword of LOCATION_KEYWORDS[category]) {\n const m = new RegExp('\\\\b' + escapeRegex(keyword) + '\\\\b', 'i').exec(lower);\n if (m && m.index < earliestPos) {\n earliestPos = m.index;\n earliestMatch = category;\n }\n }\n }\n return earliestMatch;\n}\n\n/** Verbatim port of CK-omics `parse_subcellular_location`: subcellular field is\n * scanned fully first, GO cellular-component is fallback only, else 'Unknown'. */\nexport function parseSubcellularLocation(\n subcell: string | null | undefined,\n go: string | null | undefined,\n): string {\n const subcellText = subcell == null ? '' : subcell;\n const goText = go == null ? '' : go;\n let location = findFirstLocation(subcellText);\n if (location) return location;\n location = findFirstLocation(goText);\n if (location) return location;\n return 'Unknown';\n}\n\n/** Result of parsing one UniProt stream TSV body. */\nexport interface StreamTsvResult {\n locByAcc: Map<string, string>;\n geneByAcc: Map<string, string>;\n /** Whether the winning location for an accession came from a reviewed entry. */\n reviewedByAcc: Map<string, boolean>;\n}\n\n/**\n * Pure positional parse of a UniProt stream TSV (fields order:\n * accession, cc_subcellular_location, go_c, reviewed, gene_primary). The first\n * line is the display-name header and is skipped; columns are read by POSITION\n * (`parts[0..4]`), never by header name (Pitfall 1). Within the text, the\n * priority merge is: first occurrence sets; a reviewed non-Unknown overwrites;\n * an existing Unknown is overwritten by any non-Unknown.\n */\nexport function mergeStreamTsv(text: string): StreamTsvResult {\n const locByAcc = new Map<string, string>();\n const geneByAcc = new Map<string, string>();\n const reviewedByAcc = new Map<string, boolean>();\n const lines = text.trim().split('\\n');\n for (let li = 1; li < lines.length; li++) {\n const line = lines[li];\n if (!line) continue;\n const p = line.split('\\t');\n const acc = (p[0] ?? '').trim();\n if (!acc) continue;\n const subcell = p[1] ?? '';\n const goc = p[2] ?? '';\n const reviewed = (p[3] ?? '').toLowerCase() === 'reviewed';\n const gene = (p[4] ?? '').trim();\n const cat = parseSubcellularLocation(subcell, goc);\n\n if (!locByAcc.has(acc)) {\n locByAcc.set(acc, cat);\n reviewedByAcc.set(acc, reviewed);\n } else if (reviewed && cat !== 'Unknown') {\n locByAcc.set(acc, cat);\n reviewedByAcc.set(acc, true);\n } else if (locByAcc.get(acc) === 'Unknown' && cat !== 'Unknown') {\n locByAcc.set(acc, cat);\n reviewedByAcc.set(acc, reviewed);\n }\n if (gene && (!geneByAcc.has(acc) || reviewed))\n geneByAcc.set(acc, gene);\n }\n return {locByAcc, geneByAcc, reviewedByAcc};\n}\n\n// --- Fetch + cache + D-03 fallback (Task 2) ---\n\n/** Organism g:Profiler code → NCBI (species-level) taxonomy id. Covers all 9\n * organisms in enrichment's `ORGANISM_LIST`. Species-level ids are used so the\n * UniProt `taxonomy_id:` filter (hierarchical — matches the taxon and its\n * descendants) stays inclusive of strains (e.g. E. coli K-12 under 562).\n * Only the gene-fallback pass narrows by this; accession queries do not (A1:\n * accessions are globally unique, so filtering them risks excluding valid hits). */\nexport const ORGANISM_TAXONOMY: Record<string, number> = {\n hsapiens: 9606, mmusculus: 10090, rnorvegicus: 10116, scerevisiae: 4932,\n ecoli: 562, drerio: 7955, dmelanogaster: 7227, athaliana: 3702, celegans: 6239,\n};\n\n/** userDataStorage key for the cross-session accession → category cache.\n * Exported so the volcanoOptions OK handler can peek the cache to decide\n * which pre-OK toast wording (cold vs warm) to show — see package.ts\n * volcanoOptions. */\nexport const STORE = 'proteomics-subcell-loc';\n/** Bump only if the locked keyword map ever changes (D-04: it is a contract,\n * so this is effectively fixed). Mismatch → stale cache discarded. */\nconst SCHEMA_V = '13-04-1';\nconst SCHEMA_KEY = '__schema_v';\nconst ACC_CHUNK = 100;\nconst GENE_CHUNK = 20;\n\n/** Progress callback shape used by getSubcellularLocations and forwarded by\n * ensureLocationColumn / recomputeVolcano / volcanoOptions. The dialog's\n * DG.TaskBarProgressIndicator.update is the call site that consumes this.\n *\n * - 'fetch-acc' — Pass 1 chunked accession-stream UniProt queries.\n * - 'fetch-gene' — Pass 2 reviewed-by-gene fallback queries.\n * - 'init-column' — bulk-init of the LOCATION_COL column on the DataFrame\n * (in volcano.ts) AFTER the network work completes. */\nexport type ProgressCb = (done: number, total: number,\n phase: 'fetch-acc' | 'fetch-gene' | 'init-column') => void;\n\n/** Maximum in-flight UniProt stream chunks. 6 is a compromise: 4× the\n * sequential baseline on a real ~80-chunk Spectronaut Candidates file while\n * staying well under rest.uniprot.org's documented limits. Increase only\n * with measured evidence; UniProt's stream endpoint is shared infrastructure. */\nconst FETCH_CONCURRENCY = 6;\n\n/** Wall-clock interval between incremental cache flushes during a fetch.\n * A single setInterval-driven flush from the orchestrator (not from inside\n * workers) sidesteps the per-chunk-counter race that a previous draft hit\n * when two workers reached the flush check between `await` points. */\nconst CACHE_FLUSH_INTERVAL_MS = 5000;\n\nconst VALID_CATEGORIES = new Set<string>([...Object.keys(LOCATION_KEYWORDS), 'Unknown']);\n\nconst STREAM_FIELDS = 'accession,cc_subcellular_location,go_c,reviewed,gene_primary';\nconst GENE_FIELDS = 'accession,gene_primary,cc_subcellular_location,go_c';\n\nfunction chunk<T>(arr: T[], size: number): T[][] {\n const out: T[][] = [];\n for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));\n return out;\n}\n\n/** Index-based worker pool. Maintains a shared `nextIndex` counter; launches\n * `limit` async workers; each worker pulls indices and awaits `work(items[i], i)`,\n * storing results at `results[i]`; resolves with the full results array when\n * every worker drains. Used by getSubcellularLocations Pass 1/2 to cap\n * concurrent UniProt fetchProxy calls at FETCH_CONCURRENCY.\n *\n * Exported only so the test suite can verify the concurrency cap directly\n * with synthetic deferred-promise tasks (no network). */\nexport async function runWithConcurrency<T, R>(\n items: T[], limit: number, work: (item: T, idx: number) => Promise<R>,\n): Promise<R[]> {\n const results: R[] = new Array(items.length);\n let nextIndex = 0;\n const workerCount = Math.min(Math.max(1, limit), items.length || 1);\n const workers: Promise<void>[] = [];\n for (let w = 0; w < workerCount; w++) {\n workers.push((async () => {\n while (true) {\n const i = nextIndex++;\n if (i >= items.length) return;\n results[i] = await work(items[i], i);\n }\n })());\n }\n await Promise.all(workers);\n return results;\n}\n\nfunction taxonomyClause(organism?: string): string {\n const tax = organism ? ORGANISM_TAXONOMY[organism] : undefined;\n return tax ? ` AND (taxonomy_id:${tax})` : '';\n}\n\nasync function loadCache(): Promise<Record<string, string>> {\n try {\n const raw = (await grok.dapi.userDataStorage.get(STORE)) ?? {};\n if (raw[SCHEMA_KEY] !== SCHEMA_V)\n return {[SCHEMA_KEY]: SCHEMA_V}; // stale → discard\n return raw as Record<string, string>;\n } catch {\n return {[SCHEMA_KEY]: SCHEMA_V};\n }\n}\n\n/**\n * Resolves accession → subcellular category for every requested accession.\n * Cache-first (cross-session userDataStorage map, `__schema_v`-keyed), then a\n * chunked UniProt stream fetch via grok.dapi.fetchProxy (no raw fetch — CORS),\n * then the D-03 reviewed-by-gene fallback for Unknown+gene accessions. Never\n * throws out of the fetch loop: a failed batch warns and continues.\n */\nexport async function getSubcellularLocations(\n accessions: string[],\n organism?: string,\n progress?: ProgressCb,\n): Promise<Map<string, string>> {\n const unique = [...new Set(accessions.filter((a) => a && a.length > 0))];\n const cache = await loadCache();\n\n const resolved = new Map<string, string>();\n const misses: string[] = [];\n for (const acc of unique) {\n const c = cache[acc];\n if (c !== undefined && VALID_CATEGORIES.has(c)) resolved.set(acc, c);\n else misses.push(acc);\n }\n\n const geneByAcc = new Map<string, string>();\n const fetched: Record<string, string> = {};\n // Applied ONLY to the Pass 2 gene fallback below — gene symbols are shared\n // across species, so without this a rat gene resolves to the human entry.\n const taxClause = taxonomyClause(organism);\n\n // Single timer-driven incremental flush. Workers DO NOT touch the cache —\n // they only mutate `resolved`/`fetched`/`geneByAcc`. The timer reads the\n // current `fetched` map at its tick and writes through, so a session\n // interrupted mid-fetch keeps every accession that finished. The previous\n // draft folded the flush into the per-chunk worker body and hit a documented\n // double-flush race when two workers reached the check between `await`\n // points — see plan 13-08 BLOCKER FIX notes.\n const flushCache = async (): Promise<void> => {\n if (Object.keys(fetched).length === 0) return;\n try {\n await grok.dapi.userDataStorage.put(STORE,\n {...cache, ...fetched, [SCHEMA_KEY]: SCHEMA_V});\n } catch (e: any) {\n console.warn(`Subcellular-location cache write failed: ${e?.message ?? e}`);\n }\n };\n const flushTimer = setInterval(() => { flushCache().catch(() => {}); },\n CACHE_FLUSH_INTERVAL_MS);\n\n try {\n // Pass 1: chunked accession stream queries, run with bounded concurrency.\n const accChunks = chunk(misses, ACC_CHUNK);\n const totalAcc = accChunks.length;\n let doneAcc = 0;\n await runWithConcurrency(accChunks, FETCH_CONCURRENCY, async (group) => {\n // Pass 1 is deliberately NOT taxonomy-filtered: accessions are globally\n // unique, so a wrong/mis-set organism must never exclude a valid protein.\n const q = group.map((a) => `accession:${a}`).join(' OR ');\n const url = 'https://rest.uniprot.org/uniprotkb/stream' +\n `?query=(${encodeURIComponent(q)})` +\n `&fields=${STREAM_FIELDS}&format=tsv`;\n try {\n const resp = await grok.dapi.fetchProxy(url);\n if (!resp.ok) {\n console.warn(`UniProt stream returned status ${resp.status}; continuing`);\n return;\n }\n const {locByAcc, geneByAcc: g} = mergeStreamTsv(await resp.text());\n for (const [acc, loc] of locByAcc) {\n resolved.set(acc, loc);\n fetched[acc] = loc;\n }\n for (const [acc, gene] of g) geneByAcc.set(acc, gene);\n } catch (e: any) {\n console.warn(`UniProt stream batch failed: ${e?.message ?? e}; continuing`);\n }\n // Increment AFTER the chunk completes — bounded concurrency means\n // worker order can interleave, so the callback signal is non-decreasing\n // (not strictly monotonic). Tests assert the non-decreasing invariant.\n doneAcc++;\n progress?.(doneAcc, totalAcc, 'fetch-acc');\n });\n\n // Pass 2 (D-03): reviewed-by-gene fallback for Unknown accessions with a gene.\n const geneToUnknownAccs = new Map<string, string[]>();\n for (const acc of misses) {\n const loc = resolved.get(acc) ?? 'Unknown';\n const gene = geneByAcc.get(acc);\n if (loc === 'Unknown' && gene) {\n if (!geneToUnknownAccs.has(gene)) geneToUnknownAccs.set(gene, []);\n geneToUnknownAccs.get(gene)!.push(acc);\n }\n }\n const genes = [...geneToUnknownAccs.keys()];\n const geneChunks = chunk(genes, GENE_CHUNK);\n const totalGene = geneChunks.length;\n let doneGene = 0;\n await runWithConcurrency(geneChunks, FETCH_CONCURRENCY, async (group) => {\n const q = group.map((g) => `gene_exact:${g}`).join(' OR ');\n const url = 'https://rest.uniprot.org/uniprotkb/stream' +\n `?query=(${encodeURIComponent(q)}) AND (reviewed:true)${encodeURIComponent(taxClause)}` +\n `&fields=${GENE_FIELDS}&format=tsv`;\n try {\n const resp = await grok.dapi.fetchProxy(url);\n if (!resp.ok) {\n console.warn(`UniProt gene fallback returned status ${resp.status}; continuing`);\n return;\n }\n // Positional: accession, gene_primary, cc_subcellular_location, go_c.\n const lines = (await resp.text()).trim().split('\\n');\n for (let li = 1; li < lines.length; li++) {\n const parts = lines[li].split('\\t');\n const gene = (parts[1] ?? '').trim();\n const loc = parseSubcellularLocation(parts[2] ?? '', parts[3] ?? '');\n if (!gene || loc === 'Unknown') continue;\n for (const acc of geneToUnknownAccs.get(gene) ?? []) {\n resolved.set(acc, loc);\n fetched[acc] = loc;\n }\n }\n } catch (e: any) {\n console.warn(`UniProt gene fallback batch failed: ${e?.message ?? e}; continuing`);\n }\n doneGene++;\n progress?.(doneGene, totalGene, 'fetch-gene');\n });\n\n // Anything still unresolved → Unknown (explicit, also cached so we don't\n // re-query it every session).\n for (const acc of unique) {\n if (!resolved.has(acc)) resolved.set(acc, 'Unknown');\n if (fetched[acc] === undefined) fetched[acc] = resolved.get(acc)!;\n }\n } finally {\n clearInterval(flushTimer);\n // Single final write-through. Schema invariant preserved on every flush —\n // tests assert this.\n await flushCache();\n }\n\n const out = new Map<string, string>();\n for (const acc of unique) out.set(acc, resolved.get(acc) ?? 'Unknown');\n return out;\n}\n\n// --- Cached per-accession UniProt JSON (closes the folded cache-uniprot todo;\n// uniprot-panel.ts delegates here so re-clicking a protein doesn't refetch). ---\n\nconst _entryCache = new Map<string, unknown>();\n\n/** Cached single-accession UniProt JSON fetch. Mirrors the original panel\n * discipline: grok.dapi.fetchProxy, warn + null on !resp.ok, warn + null on\n * throw. Successful and definitive-miss (non-OK) results are cached for the\n * session; transient throws are not. */\nexport async function fetchUniProtEntry(accession: string): Promise<unknown | null> {\n if (_entryCache.has(accession)) return _entryCache.get(accession) ?? null;\n const url = `https://rest.uniprot.org/uniprotkb/${encodeURIComponent(accession)}.json` +\n '?fields=accession,protein_name,gene_names,organism_name,cc_function,go';\n try {\n const resp = await grok.dapi.fetchProxy(url);\n if (!resp.ok) {\n console.warn(`UniProt fetch for ${accession} returned status ${resp.status}`);\n _entryCache.set(accession, null);\n return null;\n }\n const json = await resp.json();\n _entryCache.set(accession, json);\n return json;\n } catch (e: any) {\n console.warn(`UniProt fetch for ${accession} failed:`, e?.message ?? e);\n return null;\n }\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {findColumn} from '../utils/column-detection';\nimport {SEMTYPE} from '../utils/proteomics-types';\n\nconst PROTEIN_ID_HINTS =\n ['primary protein id', 'pg.proteingroups', 'protein id', 'uniprot', 'accession'];\n\n/**\n * Selects a protein row so the semType-registered UniProt panel populates in the\n * context panel, opens the context panel, and (best-effort) expands the UniProt\n * pane so the result is actually visible rather than one click away.\n *\n * Shared by two callers: every import handler passes the default row 0 (a small\n * \"it works\" cue the moment a file opens), and the demo passes its top\n * differential-expression hit. No-op if the table has no recognizable protein-id\n * column, so it's safe to call after any import.\n */\nexport function focusProtein(df: DG.DataFrame, rowIdx: number = 0): void {\n if (df.rowCount === 0 || rowIdx < 0 || rowIdx >= df.rowCount) return;\n const idCol = findColumn(df, SEMTYPE.PROTEIN_ID, PROTEIN_ID_HINTS);\n if (!idCol) return;\n df.currentCell = df.cell(rowIdx, idCol.name);\n grok.shell.windows.showContextPanel = true;\n void expandUniProtPane();\n}\n\n/**\n * Best-effort: expands the UniProt widget in the semantic context panel so the\n * protein result is visible immediately.\n *\n * There is no supported API to expand a semantic sub-accordion pane from a\n * package function — `onAccordionConstructed` only surfaces the top-level\n * `Actions` accordion, while the UniProt widget is rendered inside the platform's\n * semantic panel — so this reaches into the context-panel DOM. It is EXPAND-ONLY\n * (it clicks a pane header only when it lacks the `expanded` class, so it never\n * collapses a pane the user already opened) and fully guarded: if the platform\n * DOM ever changes shape, the panel simply stays collapsed, exactly as if this\n * helper were absent. The panel content itself is populated either way by the\n * current-cell selection in `focusProtein`.\n */\nasync function expandUniProtPane(): Promise<void> {\n const wanted = ['Proteomics', 'UniProt']; // group pane, then the widget inside it\n for (let attempt = 0; attempt < 12; attempt++) {\n await new Promise((r) => setTimeout(r, 250));\n try {\n const acc = document.querySelector('[d4-title=\"semantic meta.Proteomics-ProteinId\"]');\n if (!acc) continue;\n let allExpanded = true;\n for (const name of wanted) {\n const header = Array.from(acc.querySelectorAll('.d4-accordion-pane-header'))\n .find((h) => h.textContent?.trim() === name) as HTMLElement | undefined;\n if (!header) { allExpanded = false; continue; }\n if (!header.classList.contains('expanded')) {\n header.click(); // reveals the child pane on a later iteration\n allExpanded = false;\n }\n }\n if (allExpanded) return;\n } catch { /* best-effort presentation only — leave collapsed on any DOM change */ }\n }\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {focusProtein} from '../panels/protein-focus';\nimport {\n log2TransformColumns,\n copyAsLog2Columns,\n addPrimaryColumnIfNeeded,\n detectLog2Status,\n detectDelimiter,\n autoSuggestProteinIdColumn,\n autoSuggestIntensityColumns,\n autoSuggestGeneNameColumn,\n} from './shared-utils';\nimport {resolveGeneLabels} from '../utils/gene-label-resolver';\n\n/** Opens a file picker and shows the column mapping dialog for generic matrix import. */\nexport function showGenericImportDialog(): void {\n DG.Utils.openFile({\n accept: '.csv,.tsv,.txt',\n open: (file: File) => {\n const reader = new FileReader();\n reader.onload = () => {\n try {\n const text = reader.result as string;\n const delimiter = detectDelimiter(text);\n const df = DG.DataFrame.fromCsv(text, {delimiter});\n showMappingDialog(df, file.name);\n } catch (e: any) {\n grok.shell.error('Failed to parse file: ' + e.message);\n }\n };\n reader.readAsText(file);\n },\n });\n}\n\n/** Shows the column mapping dialog for a parsed DataFrame.\n * @param df - Parsed DataFrame from the imported file\n * @param fileName - Original file name for naming the output DataFrame */\nfunction showMappingDialog(df: DG.DataFrame, fileName: string): void {\n // Auto-suggest columns\n const suggestedProtein = autoSuggestProteinIdColumn(df);\n const suggestedGene = autoSuggestGeneNameColumn(df);\n const suggestedIntensityNames = autoSuggestIntensityColumns(df);\n\n // Protein ID input -- string columns only\n const proteinIdInput = ui.input.column('Protein ID', {\n table: df,\n filter: (c: DG.Column) => c.type === DG.COLUMN_TYPE.STRING,\n value: suggestedProtein ?? undefined,\n });\n\n // Gene Name input -- optional, string columns only\n const geneNameInput = ui.input.column('Gene Name (optional)', {\n table: df,\n filter: (c: DG.Column) => c.type === DG.COLUMN_TYPE.STRING,\n value: suggestedGene ?? undefined,\n nullable: true,\n });\n\n // Intensity columns multi-select — show all numeric columns, pre-select keyword matches\n const numericColNames = df.columns.toList()\n .filter((c) => c.type === DG.COLUMN_TYPE.FLOAT || c.type === DG.COLUMN_TYPE.INT || c.type === DG.COLUMN_TYPE.BIG_INT)\n .map((c) => c.name);\n const intensityColsInput = ui.input.columns('Intensity Columns', {\n table: df,\n available: numericColNames,\n value: suggestedIntensityNames.map((n) => df.col(n)!).filter((c) => c != null),\n });\n\n // Log2 detection on initial intensity columns\n const initialDetection = detectLog2Status(df, suggestedIntensityNames);\n\n // Log2 toggle -- ON means \"needs transform\" (raw intensities)\n const log2Toggle = ui.input.bool('Log2 Transform', {value: !initialDetection.isLog2});\n\n // Hint label for log2 detection message\n const hintDiv = ui.divText(initialDetection.message);\n hintDiv.style.cssText = 'font-style:italic;color:#888;margin-bottom:8px;font-size:12px;';\n\n // Preview container\n const previewContainer = document.createElement('div');\n previewContainer.style.cssText = 'border:1px solid #ddd;margin-top:8px;width:100%;';\n\n /** Updates the preview grid with currently selected columns. */\n function updatePreview(): void {\n const selectedNames: string[] = [];\n const proteinCol = proteinIdInput.value;\n if (proteinCol) selectedNames.push(proteinCol.name);\n const geneCol = geneNameInput.value;\n if (geneCol) selectedNames.push(geneCol.name);\n const intensityCols: DG.Column[] = intensityColsInput.value ?? [];\n const intensityNames = intensityCols.map((c) => c.name);\n selectedNames.push(...intensityNames);\n\n if (selectedNames.length === 0) {\n previewContainer.innerHTML = '<div style=\"padding:8px;color:#888\">Select columns to preview</div>';\n return;\n }\n\n try {\n const mask = DG.BitSet.create(df.rowCount, (i) => i < 5);\n const previewDf = df.clone(mask, selectedNames);\n const grid = DG.Viewer.grid(previewDf);\n previewContainer.innerHTML = '';\n const countLabel = ui.divText(`Preview: ${selectedNames.length} columns, 5 rows`);\n countLabel.style.cssText = 'font-size:11px;color:#888;padding:2px 4px;';\n grid.root.style.cssText = 'width:100%;height:180px;';\n previewContainer.appendChild(countLabel);\n previewContainer.appendChild(grid.root);\n } catch {\n previewContainer.innerHTML = '<div style=\"padding:8px;color:#888\">Unable to generate preview</div>';\n }\n }\n\n /** Updates log2 detection hint based on current intensity columns. */\n function updateLog2Detection(): void {\n const intensityCols: DG.Column[] = intensityColsInput.value ?? [];\n const names = intensityCols.map((c) => c.name);\n if (names.length === 0) {\n hintDiv.textContent = 'Select intensity columns';\n return;\n }\n const detection = detectLog2Status(df, names);\n hintDiv.textContent = detection.message;\n log2Toggle.value = !detection.isLog2;\n }\n\n // Wire up reactive updates\n proteinIdInput.onChanged.subscribe(() => updatePreview());\n geneNameInput.onChanged.subscribe(() => updatePreview());\n intensityColsInput.onChanged.subscribe(() => {\n updateLog2Detection();\n updatePreview();\n });\n\n // Initial preview\n updatePreview();\n\n // Build dialog\n ui.dialog('Import Generic Matrix')\n .add(proteinIdInput)\n .add(geneNameInput)\n .add(intensityColsInput)\n .add(log2Toggle)\n .add(ui.div([hintDiv]))\n .add(previewContainer)\n .onOK(async () => {\n const proteinCol = proteinIdInput.value;\n if (!proteinCol) {\n grok.shell.warning('Please select a Protein ID column');\n return;\n }\n\n const intensityCols: DG.Column[] = intensityColsInput.value ?? [];\n const intensityNames = intensityCols.map((c) => c.name);\n if (intensityNames.length === 0) {\n grok.shell.warning('Please select at least one intensity column');\n return;\n }\n\n // Assign semantic types\n proteinCol.semType = SEMTYPE.PROTEIN_ID;\n\n const geneCol = geneNameInput.value;\n if (geneCol)\n geneCol.semType = SEMTYPE.GENE_SYMBOL;\n\n // Log2 transform or copy\n if (log2Toggle.value)\n log2TransformColumns(df, intensityNames);\n else\n copyAsLog2Columns(df, intensityNames);\n\n // Primary columns (splits semicolon-delimited values)\n addPrimaryColumnIfNeeded(df, proteinCol.name, 'Primary Protein ID', SEMTYPE.PROTEIN_ID);\n if (geneCol)\n addPrimaryColumnIfNeeded(df, geneCol.name, 'Primary Gene Name', SEMTYPE.GENE_SYMBOL);\n\n // Source tag\n df.setTag('proteomics.source', 'generic');\n\n await resolveGeneLabels(df);\n\n // Name from file\n df.name = fileName.replace(/\\.[^.]+$/, '');\n\n // Open in table view\n grok.shell.addTableView(df);\n grok.shell.info(`Imported ${df.rowCount} proteins from ${fileName}`);\n focusProtein(df);\n })\n .show();\n}\n","import * as DG from 'datagrok-api/dg';\nimport {getGroups} from '../analysis/experiment-setup';\nimport {findColumn} from '../utils/column-detection';\nimport {SEMTYPE} from '../utils/proteomics-types';\n\n/** Z-score normalize a value given mean and standard deviation. */\nfunction zScore(value: number, mean: number, std: number): number {\n return std > 0 ? (value - mean) / std : 0;\n}\n\n/**\n * Creates an expression heatmap (Grid in heatmap mode) on a cloned DataFrame\n * containing only the top-N most significant proteins. The clone isolates\n * the heatmap's filter, z-score columns, and sort order from the original\n * DataFrame so that other viewers (volcano plot) are not affected.\n *\n * Rows are hierarchically clustered via the Dendrogram package service if available,\n * otherwise sorted by adj.p-value ascending (significance-based fallback).\n *\n * Z-score normalization uses statistics computed across ALL rows of the original\n * DataFrame for statistical correctness, but z-score columns are only added to the\n * cloned DataFrame.\n */\nexport async function createExpressionHeatmap(\n df: DG.DataFrame,\n options?: {topN?: number; labelCol?: string; title?: string},\n): Promise<DG.Grid> {\n const topN = options?.topN ?? 50;\n const labelColName = options?.labelCol ?? 'Gene Name';\n\n // 1. Check prerequisites\n if (df.getTag('proteomics.de_complete') !== 'true')\n throw new Error('Differential expression must be run first');\n\n const groups = getGroups(df);\n if (!groups)\n throw new Error('Experimental groups must be annotated first');\n\n // 2. Select top N proteins by adj.p-value (ascending)\n const adjPCol = df.col('adj.p-value');\n if (!adjPCol)\n throw new Error('adj.p-value column not found');\n\n // Collect row indices with non-null adj.p-value, sorted ascending\n const indexedPValues: {idx: number; pVal: number}[] = [];\n for (let i = 0; i < df.rowCount; i++) {\n if (!adjPCol.isNone(i))\n indexedPValues.push({idx: i, pVal: adjPCol.get(i) as number});\n }\n indexedPValues.sort((a, b) => a.pVal - b.pVal);\n\n const topNIndices = new Set<number>();\n for (let i = 0; i < Math.min(topN, indexedPValues.length); i++)\n topNIndices.add(indexedPValues[i].idx);\n\n // 3. Clone the DataFrame with only top-N rows (filter isolation)\n const filter = DG.BitSet.create(df.rowCount);\n for (const idx of topNIndices)\n filter.set(idx, true);\n const heatmapDf = df.clone(filter);\n\n // 4. Compute z-score columns on the cloned DataFrame\n // Statistics (mean, std) are computed across ALL rows of the original df for correctness,\n // then z-scores are computed on the cloned rows only.\n const allIntensityCols = [...groups.group1.columns, ...groups.group2.columns];\n const zScoreColNames: string[] = [];\n\n for (const colName of allIntensityCols) {\n const zColName = `_zscore_${colName}`;\n zScoreColNames.push(zColName);\n\n const srcColOrig = df.col(colName);\n if (!srcColOrig) continue;\n\n // Compute mean and std across all non-null values in the ORIGINAL column.\n // Use direct typed-array access to skip the per-row JS->native interop.\n const origRaw = srcColOrig.getRawData() as Float32Array | Float64Array;\n let sum = 0;\n let sumSq = 0;\n let count = 0;\n for (let i = 0; i < df.rowCount; i++) {\n const v = origRaw[i];\n if (v !== DG.FLOAT_NULL) {\n sum += v;\n sumSq += v * v;\n count++;\n }\n }\n\n const colMean = count > 0 ? sum / count : 0;\n const variance = count > 1 ? (sumSq - sum * sum / count) / (count - 1) : 0;\n const colStd = Math.sqrt(variance);\n\n // Apply z-scores to the cloned DataFrame\n const srcColClone = heatmapDf.col(colName);\n if (!srcColClone) continue;\n\n const srcRaw = srcColClone.getRawData() as Float32Array | Float64Array;\n const zCol = heatmapDf.columns.addNewFloat(zColName);\n zCol.init((i) => srcRaw[i] === DG.FLOAT_NULL ? DG.FLOAT_NULL : zScore(srcRaw[i], colMean, colStd));\n }\n\n // 5. Create Grid on the cloned DataFrame\n const grid = heatmapDf.plot.grid();\n\n // 6. Column visibility -- hide everything, then show label + z-score columns\n for (let i = 0; i < grid.columns.length; i++) {\n const gc = grid.columns.byIndex(i);\n if (gc) gc.visible = false;\n }\n\n // Show label column (gene symbol preferred, protein ID as fallback)\n const labelCol = findColumn(heatmapDf, SEMTYPE.GENE_SYMBOL, [labelColName.toLowerCase(), 'gene symbol'])\n ?? findColumn(heatmapDf, SEMTYPE.PROTEIN_ID, ['protein id', 'majority protein id', 'accession']);\n if (labelCol) {\n const labelGc = grid.columns.byName(labelCol.name);\n if (labelGc) labelGc.visible = true;\n }\n\n // Show z-score columns in group order (control left, treatment right)\n const group1ZCols = groups.group1.columns.map((c) => `_zscore_${c}`);\n const group2ZCols = groups.group2.columns.map((c) => `_zscore_${c}`);\n\n for (const zColName of [...group1ZCols, ...group2ZCols]) {\n const gc = grid.columns.byName(zColName);\n if (gc) gc.visible = true;\n }\n\n // 7. Attempt hierarchical clustering via Dendrogram package; fall back to\n // significance-based row ordering if the package is unavailable or its\n // function signature has drifted.\n let clustered = false;\n const pi = DG.TaskBarProgressIndicator.create('Calculating distance matrix...');\n try {\n const dFunc = DG.Func.find({package: 'Dendrogram', name: 'hierarchicalClustering'})[0];\n if (!dFunc)\n throw new Error('Dendrogram package not installed (hierarchicalClustering not found)');\n if (dFunc.inputs.length !== 4)\n throw new Error(`Dendrogram.hierarchicalClustering signature changed (expected 4 inputs, got ${dFunc.inputs.length})`);\n await dFunc.apply({\n df: grid, colNameList: zScoreColNames,\n distance: 'euclidean', linkage: 'complete',\n });\n clustered = true;\n } catch (e: any) {\n console.warn(`Dendrogram clustering unavailable, falling back to significance-based row ordering: ${e?.message ?? e}`);\n } finally {\n pi.close();\n }\n\n if (!clustered) {\n // Sort by adjusted p-value ascending (most significant first). R scripts\n // sometimes return the column as `adj.p.value` (dots) instead of `adj.p-value`.\n const sortCol = heatmapDf.col('adj.p-value') ? 'adj.p-value' :\n (heatmapDf.col('adj.p.value') ? 'adj.p.value' : null);\n if (sortCol)\n grid.sort([sortCol]);\n }\n\n // 8. Configure Grid for heatmap display\n grid.props.isHeatmap = true;\n grid.props.isGrid = false;\n\n if (options?.title)\n grid.setOptions({title: options.title});\n\n return grid;\n}\n","import * as DG from 'datagrok-api/dg';\nimport {GroupAssignment} from '../analysis/experiment-setup';\nimport {computePCA} from '../analysis/pca';\n\n/** Local interface for area annotation region (may not be in installed datagrok-api types). */\ninterface AreaAnnotationRegionDef {\n type: string;\n area: [number, number][];\n fillColor: string;\n opacity: number;\n outlineColor: string;\n outlineWidth: number;\n x: string;\n y: string;\n}\n\n/** Group colors for PCA plot ellipses and styling. */\nconst GROUP_COLORS: string[] = ['#2196F3', '#FF5722'];\n\n/** Compute 95% confidence ellipse polygon points for a set of 2D points.\n * Returns an array of [x, y] pairs approximating the ellipse. */\nfunction confidenceEllipse(\n xVals: number[],\n yVals: number[],\n nPoints: number = 64,\n): [number, number][] | null {\n const n = xVals.length;\n if (n < 3)\n return null;\n\n // Compute means\n let cx = 0;\n let cy = 0;\n for (let i = 0; i < n; i++) {\n cx += xVals[i];\n cy += yVals[i];\n }\n cx /= n;\n cy /= n;\n\n // Compute 2x2 covariance matrix\n let sxx = 0;\n let sxy = 0;\n let syy = 0;\n for (let i = 0; i < n; i++) {\n const dx = xVals[i] - cx;\n const dy = yVals[i] - cy;\n sxx += dx * dx;\n sxy += dx * dy;\n syy += dy * dy;\n }\n sxx /= (n - 1);\n sxy /= (n - 1);\n syy /= (n - 1);\n\n // Eigendecompose 2x2 matrix analytically\n const trace = sxx + syy;\n const det = sxx * syy - sxy * sxy;\n const disc = Math.sqrt(Math.max(trace * trace / 4 - det, 0));\n const lambda1 = trace / 2 + disc;\n const lambda2 = trace / 2 - disc;\n\n if (lambda1 <= 0 || lambda2 <= 0)\n return null;\n\n // Eigenvector for lambda1\n let angle: number;\n if (Math.abs(sxy) > 1e-12)\n angle = Math.atan2(lambda1 - sxx, sxy);\n else\n angle = sxx >= syy ? 0 : Math.PI / 2;\n\n // Chi-squared critical value for 2 DOF at 95% confidence\n const chiSq95 = 5.991;\n\n // Semi-axes scaled by chi-squared\n const a = Math.sqrt(lambda1 * chiSq95);\n const b = Math.sqrt(lambda2 * chiSq95);\n\n // Generate ellipse polygon\n const points: [number, number][] = [];\n const cosA = Math.cos(angle);\n const sinA = Math.sin(angle);\n for (let i = 0; i < nPoints; i++) {\n const t = (2 * Math.PI * i) / nPoints;\n const ex = a * Math.cos(t);\n const ey = b * Math.sin(t);\n const x = cx + cosA * ex - sinA * ey;\n const y = cy + sinA * ex + cosA * ey;\n points.push([x, y]);\n }\n\n return points;\n}\n\n/** Creates a PCA plot (ScatterPlotViewer) on a sample-level DataFrame.\n * Computes PCA from intensity columns and colors points by experimental group.\n * Returns the viewer; the caller is responsible for adding the pcaDf to a view. */\nexport function createPcaPlot(\n df: DG.DataFrame,\n intensityCols: string[],\n groupAssignment: GroupAssignment,\n title?: string,\n): {viewer: DG.ScatterPlotViewer; pcaDf: DG.DataFrame} {\n const {pcaDf, varianceExplained} = computePCA(df, intensityCols, groupAssignment);\n\n // Find PC column names (they include variance in the name).\n const pc1ColName = pcaDf.columns.toList().find((c) => c.name.startsWith('PC1'))?.name;\n const pc2ColName = pcaDf.columns.toList().find((c) => c.name.startsWith('PC2'))?.name;\n if (!pc1ColName || !pc2ColName)\n throw new Error('PCA did not produce PC1/PC2 columns — too few samples?');\n\n const sp = pcaDf.plot.scatter({\n x: pc1ColName,\n y: pc2ColName,\n color: 'Group',\n });\n\n // Label all sample points (typically <50 samples in proteomics)\n sp.props.labelColumnNames = ['SampleName'];\n sp.props.displayLabels = 'Always';\n\n // Attempt to add 95% confidence ellipses per group\n try {\n const pc1Col = pcaDf.col(pc1ColName)!;\n const pc2Col = pcaDf.col(pc2ColName)!;\n const groupCol = pcaDf.col('Group')!;\n const groups = [groupAssignment.group1.name, groupAssignment.group2.name];\n\n for (let g = 0; g < groups.length; g++) {\n const groupName = groups[g];\n const xVals: number[] = [];\n const yVals: number[] = [];\n for (let i = 0; i < pcaDf.rowCount; i++) {\n if (groupCol.get(i) === groupName) {\n xVals.push(pc1Col.get(i) as number);\n yVals.push(pc2Col.get(i) as number);\n }\n }\n\n const ellipsePoints = confidenceEllipse(xVals, yVals);\n if (ellipsePoints) {\n const color = GROUP_COLORS[g % GROUP_COLORS.length];\n const region: AreaAnnotationRegionDef = {\n type: 'area',\n area: ellipsePoints,\n fillColor: color,\n opacity: 0.15,\n outlineColor: color,\n outlineWidth: 1,\n x: pc1ColName,\n y: pc2ColName,\n };\n // annotationRegions API may not be available in all datagrok-api versions\n (sp.meta as any).annotationRegions?.add(region);\n }\n }\n } catch (e: any) {\n // Ellipse rendering is best-effort — the annotationRegions API may not be\n // exposed in the installed datagrok-api. Log the underlying error so this\n // doesn't silently mask unrelated bugs in the ellipse math or column reads.\n console.warn('PCA: could not add confidence ellipses:', e?.message ?? e);\n }\n\n if (title)\n sp.setOptions({title});\n\n return {viewer: sp, pcaDf};\n}\n","import * as DG from 'datagrok-api/dg';\nimport {GroupAssignment} from './experiment-setup';\n\n/** Transpose a matrix (rows x cols) -> (cols x rows). */\nfunction transpose(matrix: number[][], rows: number, cols: number): number[][] {\n const result: number[][] = [];\n for (let j = 0; j < cols; j++) {\n const row: number[] = new Array(rows);\n for (let i = 0; i < rows; i++)\n row[i] = matrix[i][j];\n result.push(row);\n }\n return result;\n}\n\n/** Multiply matrices A (m x n) and B (n x p) -> C (m x p). */\nfunction matmul(A: number[][], B: number[][], m: number, n: number, p: number): number[][] {\n const C: number[][] = [];\n for (let i = 0; i < m; i++) {\n const row = new Array(p).fill(0);\n for (let k = 0; k < n; k++) {\n const aik = A[i][k];\n for (let j = 0; j < p; j++)\n row[j] += aik * B[k][j];\n }\n C.push(row);\n }\n return C;\n}\n\n/** Jacobi eigendecomposition for a symmetric matrix.\n * Returns eigenvalues and eigenvectors sorted descending by eigenvalue. */\nfunction jacobi(matrix: number[][], n: number): {eigenvalues: number[]; eigenvectors: number[][]} {\n // Deep copy the matrix\n const A: number[][] = matrix.map((row) => [...row]);\n\n // Initialize eigenvectors as identity matrix\n const V: number[][] = [];\n for (let i = 0; i < n; i++) {\n const row = new Array(n).fill(0);\n row[i] = 1;\n V.push(row);\n }\n\n const maxIter = 100;\n const tolerance = 1e-10;\n let converged = false;\n\n for (let iter = 0; iter < maxIter; iter++) {\n // Find largest off-diagonal element\n let maxVal = 0;\n let p = 0;\n let q = 1;\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n if (Math.abs(A[i][j]) > maxVal) {\n maxVal = Math.abs(A[i][j]);\n p = i;\n q = j;\n }\n }\n }\n\n if (maxVal < tolerance) {\n converged = true;\n break;\n }\n\n // Compute rotation angle\n const theta = (A[q][q] - A[p][p]) / (2 * A[p][q]);\n const t = Math.sign(theta) / (Math.abs(theta) + Math.sqrt(theta * theta + 1));\n const c = 1 / Math.sqrt(t * t + 1);\n const s = t * c;\n\n // Apply rotation to A\n const app = A[p][p];\n const aqq = A[q][q];\n const apq = A[p][q];\n\n A[p][p] = c * c * app - 2 * s * c * apq + s * s * aqq;\n A[q][q] = s * s * app + 2 * s * c * apq + c * c * aqq;\n A[p][q] = 0;\n A[q][p] = 0;\n\n for (let i = 0; i < n; i++) {\n if (i !== p && i !== q) {\n const aip = A[i][p];\n const aiq = A[i][q];\n A[i][p] = c * aip - s * aiq;\n A[p][i] = A[i][p];\n A[i][q] = s * aip + c * aiq;\n A[q][i] = A[i][q];\n }\n }\n\n // Update eigenvectors\n for (let i = 0; i < n; i++) {\n const vip = V[i][p];\n const viq = V[i][q];\n V[i][p] = c * vip - s * viq;\n V[i][q] = s * vip + c * viq;\n }\n }\n\n if (!converged)\n console.warn(`PCA Jacobi did not converge in ${maxIter} iterations (n=${n}); results may be approximate`);\n\n // Extract eigenvalues and sort descending\n const eigenvalues = new Array(n);\n for (let i = 0; i < n; i++)\n eigenvalues[i] = A[i][i];\n\n const indices = Array.from({length: n}, (_, i) => i);\n indices.sort((a, b) => eigenvalues[b] - eigenvalues[a]);\n\n const sortedEigenvalues = indices.map((i) => eigenvalues[i]);\n const sortedEigenvectors: number[][] = [];\n for (let i = 0; i < n; i++) {\n const row = new Array(n);\n for (let j = 0; j < n; j++)\n row[j] = V[i][indices[j]];\n sortedEigenvectors.push(row);\n }\n\n return {eigenvalues: sortedEigenvalues, eigenvectors: sortedEigenvectors};\n}\n\n/** Compute sample-level PCA on intensity columns.\n * Returns a NEW sample-level DataFrame (rows = samples, not proteins)\n * and the variance explained percentages. */\nexport function computePCA(\n df: DG.DataFrame,\n intensityCols: string[],\n groupAssignment: GroupAssignment,\n nComponents: number = 2,\n): {pcaDf: DG.DataFrame; varianceExplained: number[]} {\n const nSamples = intensityCols.length;\n const nProteins = df.rowCount;\n\n // Step 1: Build transposed matrix (nSamples x nProteins)\n // Each row = one sample, each column = one protein's intensity across that sample\n const matrix: number[][] = [];\n\n // Compute protein means for imputation (mean across samples for each protein)\n const proteinMeans: number[] = new Array(nProteins).fill(0);\n const proteinCounts: number[] = new Array(nProteins).fill(0);\n\n for (const colName of intensityCols) {\n const col = df.col(colName);\n if (!col) continue;\n for (let i = 0; i < nProteins; i++) {\n if (!col.isNone(i)) {\n proteinMeans[i] += col.get(i) as number;\n proteinCounts[i]++;\n }\n }\n }\n for (let i = 0; i < nProteins; i++)\n proteinMeans[i] = proteinCounts[i] > 0 ? proteinMeans[i] / proteinCounts[i] : 0;\n\n // Build sample rows with imputation\n for (const colName of intensityCols) {\n const col = df.col(colName);\n const row: number[] = new Array(nProteins);\n for (let i = 0; i < nProteins; i++) {\n if (!col || col.isNone(i))\n row[i] = proteinMeans[i];\n else\n row[i] = col.get(i) as number;\n }\n matrix.push(row);\n }\n\n // Step 2: Center each column (protein) by subtracting its mean across samples\n const colMeans: number[] = new Array(nProteins).fill(0);\n for (let j = 0; j < nProteins; j++) {\n for (let i = 0; i < nSamples; i++)\n colMeans[j] += matrix[i][j];\n colMeans[j] /= nSamples;\n }\n for (let i = 0; i < nSamples; i++) {\n for (let j = 0; j < nProteins; j++)\n matrix[i][j] -= colMeans[j];\n }\n\n // Step 3: Compute covariance matrix S (nSamples x nSamples)\n // S = X * X^T / (nProteins - 1) -- small matrix since nSamples << nProteins\n const Xt = transpose(matrix, nSamples, nProteins);\n const S = matmul(matrix, Xt, nSamples, nProteins, nSamples);\n const divisor = nProteins > 1 ? nProteins - 1 : 1;\n for (let i = 0; i < nSamples; i++) {\n for (let j = 0; j < nSamples; j++)\n S[i][j] /= divisor;\n }\n\n // Step 4: Eigendecompose S\n const {eigenvalues, eigenvectors} = jacobi(S, nSamples);\n\n // Step 5: PC scores are the eigenvectors scaled by sqrt(eigenvalue)\n const scores: number[][] = [];\n for (let i = 0; i < nSamples; i++) {\n const row: number[] = [];\n for (let k = 0; k < Math.min(nComponents, nSamples); k++) {\n const scale = eigenvalues[k] > 0 ? Math.sqrt(eigenvalues[k]) : 0;\n row.push(eigenvectors[i][k] * scale);\n }\n scores.push(row);\n }\n\n // Step 6: Compute variance explained. Clamp eigenvalues to >= 0 for both\n // totalVariance and per-PC pct so numerical noise can't produce negative percentages.\n const totalVariance = eigenvalues.reduce((sum, v) => sum + Math.max(v, 0), 0);\n const varianceExplained: number[] = [];\n for (let k = 0; k < Math.min(nComponents, nSamples); k++) {\n const pct = totalVariance > 0 ? (Math.max(eigenvalues[k], 0) / totalVariance) * 100 : 0;\n varianceExplained.push(Math.round(pct * 10) / 10);\n }\n\n // Step 7: Create sample-level DataFrame. PCA on <2 samples is meaningless;\n // produce stable column labels rather than \"PC1 (NaN%)\".\n const pc1Pct = varianceExplained.length > 0 && isFinite(varianceExplained[0]) ? varianceExplained[0] : 0;\n const pc1Name = nSamples >= 2 ? `PC1 (${pc1Pct}%)` : 'PC1';\n const pc2Pct = varianceExplained.length >= 2 && isFinite(varianceExplained[1]) ? varianceExplained[1] : 0;\n const pc2Name = nComponents >= 2 && varianceExplained.length >= 2 && nSamples >= 2\n ? `PC2 (${pc2Pct}%)`\n : 'PC2';\n\n const sampleNames = DG.Column.fromStrings('SampleName', intensityCols);\n const pc1Col = DG.Column.fromFloat32Array(pc1Name,\n new Float32Array(scores.map((s) => s[0])));\n const columns: DG.Column[] = [sampleNames, pc1Col];\n\n if (nComponents >= 2) {\n const pc2Col = DG.Column.fromFloat32Array(pc2Name,\n new Float32Array(scores.map((s) => s.length > 1 ? s[1] : 0)));\n columns.push(pc2Col);\n }\n\n // Map each sample to its group\n const groupNames: string[] = intensityCols.map((colName) => {\n if (groupAssignment.group1.columns.includes(colName))\n return groupAssignment.group1.name;\n if (groupAssignment.group2.columns.includes(colName))\n return groupAssignment.group2.name;\n return 'Unknown';\n });\n const groupCol = DG.Column.fromStrings('Group', groupNames);\n columns.push(groupCol);\n\n const pcaDf = DG.DataFrame.fromColumns(columns);\n pcaDf.name = 'PCA';\n\n return {pcaDf, varianceExplained};\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {getGroups} from '../analysis/experiment-setup';\nimport {ensureDirectionColumn} from './volcano';\nimport {DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\nimport {\n getIntensityColumns,\n computeMA,\n computeLoessTrend,\n computeCV,\n createMissingnessMatrix,\n unpivotIntensities,\n computeMissingBarData,\n} from './qc-computations';\n\n/** Columns added by QC computations that should be cleaned up on re-run.\n * `direction` is NOT included here: it is shared with the volcano plot, which\n * updates it in-place, and ensureDirectionColumn(...) below overwrites cells\n * rather than re-adding the column. Removing it would break any open volcano\n * viewer bound to the column reference. */\nconst QC_COLUMNS = ['M', 'A', 'MA_trend', 'CV_group1', 'meanInt_group1', 'CV_group2', 'meanInt_group2'];\n\n/** Opens a QC dashboard with all QC viewers docked in a tiled layout.\n * Requires group annotations (shows warning if missing). */\nexport function openQcDashboard(df: DG.DataFrame): void {\n const pi = DG.TaskBarProgressIndicator.create('Creating QC dashboard...');\n try {\n // 1. Prerequisite check: groups must be annotated\n const groups = getGroups(df);\n if (!groups) {\n grok.shell.warning('Annotate experimental groups first (Proteomics | Annotate Experiment)');\n return;\n }\n\n // 2. Clean up previous QC columns (allows re-running)\n for (const name of QC_COLUMNS) {\n if (df.columns.contains(name))\n df.columns.remove(name);\n }\n\n // 3. Get intensity columns\n const intensityCols = getIntensityColumns(df);\n if (intensityCols.length === 0) {\n grok.shell.warning('No log2 intensity columns found');\n return;\n }\n\n // 4. Compute MA values\n computeMA(df, groups);\n\n // 5. Compute loess/moving-average trend\n computeLoessTrend(df);\n\n // 6. Compute CV per group\n computeCV(df, groups.group1.columns, 'CV_group1', 'meanInt_group1');\n computeCV(df, groups.group2.columns, 'CV_group2', 'meanInt_group2');\n\n // Get the current table view\n const tv = grok.shell.tv;\n if (!tv) {\n grok.shell.warning('No table view open');\n return;\n }\n\n // 7. MA scatter plot\n const maPlotOptions: Record<string, any> = {\n xColumnName: 'A',\n yColumnName: 'M',\n title: 'MA Plot',\n markerDefaultSize: 2,\n };\n\n // Conditional coloring by direction when DE is available\n if (df.getTag('proteomics.de_complete') === 'true') {\n try {\n const dirColName = ensureDirectionColumn(df, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD);\n maPlotOptions['colorColumnName'] = dirColName;\n } catch (_e) {\n // DE columns may not exist despite tag -- skip coloring\n }\n }\n\n const maPlot = tv.addViewer(DG.VIEWER.SCATTER_PLOT, maPlotOptions);\n\n // Add M=0 reference line for MA plot. Drop any prior M=0 lines first so\n // repeated QC dashboard opens don't stack duplicates on the DataFrame.\n const maFormula = '${M} = 0';\n df.meta.formulaLines.items = df.meta.formulaLines.items.filter((line) => line.formula !== maFormula);\n df.meta.formulaLines.addLine({\n formula: maFormula,\n color: '#888888',\n width: 1,\n visible: true,\n });\n\n // 7b. MA trend line as a separate scatter plot with line markers\n const maTrend = tv.addViewer(DG.VIEWER.SCATTER_PLOT, {\n xColumnName: 'A',\n yColumnName: 'MA_trend',\n title: 'MA Trend',\n markerDefaultSize: 1,\n });\n\n // 8. CV scatter plot (group1 by default)\n const cvPlot = tv.addViewer(DG.VIEWER.SCATTER_PLOT, {\n xColumnName: 'meanInt_group1',\n yColumnName: 'CV_group1',\n title: 'CV Plot',\n markerDefaultSize: 2,\n });\n\n // 9. Sample correlation plot\n const corrPlot = tv.addViewer(DG.VIEWER.CORR_PLOT, {\n xColumnNames: intensityCols,\n yColumnNames: intensityCols,\n title: 'Sample Correlation',\n });\n\n // 10. Missing values heatmap (separate DataFrame -- no addTable to avoid circular JSON)\n const missDf = createMissingnessMatrix(df, intensityCols);\n const missGrid = DG.Viewer.grid(missDf);\n missGrid.props.allowColSelection = false;\n\n // 11. Missing values bar chart (separate DataFrame -- use factory to bind correctly)\n const barDf = computeMissingBarData(df, intensityCols, groups);\n const missBar = DG.Viewer.barChart(barDf, {\n splitColumnName: 'Sample',\n valueColumnName: 'MissingPct',\n stackColumnName: 'Group',\n } as any);\n\n // 12. Box plot for intensity distributions (separate DataFrame -- use factory to bind correctly)\n const longDf = unpivotIntensities(df, intensityCols);\n const boxPlot = DG.Viewer.boxPlot(longDf, {\n valueColumnName: 'Intensity',\n categoryColumnName: 'Sample',\n } as any);\n\n // 13. Dock layout -- two themed tab stacks so every chart stays full-size.\n // Seven heterogeneous QC charts can't all be legible tiled at once (chaining\n // them RIGHT squeezes the last ones to nothing), so group by QC theme and tab\n // within each region (DOCK_TYPE.FILL): the active chart fills the whole\n // region instead of being cramped.\n // * Top-right region -- per-protein diagnostics: MA / MA trend / CV\n // * Bottom-right region -- per-sample QC: correlation / distributions / missingness\n // The data grid keeps the left quarter.\n const dm = tv.dockManager;\n\n // Per-protein stack (top-right). RIGHT of root at 0.75 leaves the grid a quarter.\n const protNode = dm.dock(maPlot, DG.DOCK_TYPE.RIGHT, null, 'MA Plot', 0.75);\n dm.dock(maTrend, DG.DOCK_TYPE.FILL, protNode, 'MA Trend');\n dm.dock(cvPlot, DG.DOCK_TYPE.FILL, protNode, 'CV Plot');\n\n // Per-sample stack (bottom-right), splitting the right region in half vertically.\n const sampleNode = dm.dock(corrPlot, DG.DOCK_TYPE.DOWN, protNode, 'Sample Correlation', 0.5);\n dm.dock(boxPlot, DG.DOCK_TYPE.FILL, sampleNode, 'Intensity Distributions');\n dm.dock(missBar, DG.DOCK_TYPE.FILL, sampleNode, 'Missing % per Sample');\n dm.dock(missGrid, DG.DOCK_TYPE.FILL, sampleNode, 'Missing Values');\n\n // FILL docking activates the LAST-docked tab; make each stack default to its\n // headline chart instead (MA Plot / Sample Correlation). setActiveChild lives\n // on the parent tab container. Best-effort — a layout that isn't tabbed (e.g.\n // a future single-viewer variant) simply keeps its default active tab.\n const activateTab = (v: DG.Viewer): void => {\n try {\n const node = dm.findNode(v.root);\n if (node?.parent) node.parent.container.setActiveChild(node.container);\n } catch { /* best-effort */ }\n };\n activateTab(maPlot);\n activateTab(corrPlot);\n } finally {\n pi.close();\n }\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {\n META_COLUMNS, PUBLISHED_TAGS, PublishedMetadata,\n isPublished, getPublishedMetadata, buildMailtoUrl,\n} from '../publishing/publish-state';\nimport {findHostDataFrameForProtein} from './uniprot-panel';\nimport {getGroups} from '../analysis/experiment-setup';\n\n/**\n * Reviewer-side audit context panel. Opens when a reviewer clicks a protein\n * row in a published Project. Surfaces the metadata the analyst stamped at\n * publish time (DE method, thresholds, group names, target, share date, sharer\n * name) plus PUB-13 mailto button. First-line `isPublished(df)` guard ensures\n * it does NOT render on the analyst's live working DataFrame.\n *\n * Reads metadata column FIRST, tag SECOND per Pitfall 3 — the column survives\n * the serializer; the tag is a defensive secondary. All user-facing strings\n * pass the Pitfall 14 biologist-jargon audit. Imports {@link buildMailtoUrl}\n * from `../publishing/publish-state` rather than `../publishing/share-dialog`\n * (B-1 fix — avoids the wave-2 → wave-4 dependency cycle).\n */\n\n/** Human-friendly expansion of the DE method ID for the audit \"Method\" row.\n * CONTEXT.md domain pin: narrate what an expert would assume known. */\nfunction methodLabel(method: string): string {\n switch (method) {\n case 'limma': return 'limma — moderated t-test';\n case 'deqms': return 'DEqMS — peptide-count-aware moderated t-test';\n case 't-test': return 'Welch t-test';\n case 'spectronaut': return 'Spectronaut Candidates (pre-computed DE)';\n default: return method || '(unknown method)';\n }\n}\n\nfunction dateSlice(d: Date | string | number | null | undefined): string {\n if (d == null) return 'unknown date';\n try {\n if (d instanceof Date) {\n if (Number.isNaN(d.getTime())) return 'unknown date';\n return d.toISOString().slice(0, 10);\n }\n const parsed = new Date(d);\n if (Number.isNaN(parsed.getTime())) return 'unknown date';\n return parsed.toISOString().slice(0, 10);\n } catch {\n return 'unknown date';\n }\n}\n\nfunction fieldRow(label: string, value: string): HTMLDivElement {\n const labelEl = ui.divText(label);\n labelEl.style.fontWeight = '600';\n labelEl.style.fontSize = '12px';\n labelEl.style.color = '#666';\n const valueEl = ui.divText(value);\n valueEl.style.marginBottom = '8px';\n const row = ui.div([labelEl, valueEl]);\n row.style.marginBottom = '6px';\n return row;\n}\n\nfunction readSharerEmail(df: DG.DataFrame, meta: PublishedMetadata): string | null {\n if (meta.publishedByEmail != null && meta.publishedByEmail !== '')\n return meta.publishedByEmail;\n try {\n const col = df.col(META_COLUMNS.PUBLISHED_BY_EMAIL);\n if (col != null) {\n const v = col.get(0);\n if (v != null && v !== '') return String(v);\n }\n } catch { /* fall through */ }\n try {\n const t = df.getTag(PUBLISHED_TAGS.PUBLISHED_BY_EMAIL);\n if (t) return t;\n } catch { /* fall through */ }\n return null;\n}\n\nexport function publishedAnalysisPanel(proteinId: string): DG.Widget {\n const df = findHostDataFrameForProtein(proteinId);\n if (df == null) return new DG.Widget(ui.div());\n if (!isPublished(df)) return new DG.Widget(ui.div());\n\n const meta = getPublishedMetadata(df);\n if (meta == null)\n return new DG.Widget(ui.divText('Shared analysis metadata unavailable. Ask the sharer to re-share.'));\n\n const body = ui.div();\n body.style.padding = '8px 4px';\n\n if (meta.supersededBy != null && meta.supersededBy !== '') {\n const newerLink = ui.link('Newer version available — open it', async () => {\n try {\n const newer = await grok.dapi.projects.find(meta.supersededBy!);\n await newer.open();\n } catch (e) {\n grok.shell.warning(`Could not open the newer version: ${(e as Error)?.message ?? e}`);\n }\n });\n const banner = ui.div([newerLink]);\n banner.style.padding = '8px';\n banner.style.marginBottom = '10px';\n banner.style.backgroundColor = '#fff8dc';\n banner.style.borderRadius = '4px';\n body.appendChild(banner);\n }\n\n body.appendChild(ui.h2('Shared analysis details'));\n\n const groups = getGroups(df);\n const comparison = groups != null\n ? `${groups.group2.name} vs ${groups.group1.name}`\n : 'unavailable';\n\n const fcFold = Number.isFinite(meta.fcThreshold) ? Math.pow(2, meta.fcThreshold) : NaN;\n const fcLabel = Number.isFinite(meta.fcThreshold)\n ? `log2(${meta.fcThreshold}) (${Number.isFinite(fcFold) ? fcFold.toFixed(2) : 'NaN'}-fold)`\n : '(unknown)';\n const pLabel = Number.isFinite(meta.pThreshold)\n ? `${meta.pThreshold} (FDR-adjusted)`\n : '(unknown)';\n\n body.appendChild(fieldRow('Target', meta.target || '(unknown)'));\n body.appendChild(fieldRow('Shared', dateSlice(meta.publishedAt)));\n body.appendChild(fieldRow('Shared by', meta.publishedBy || '(unknown)'));\n body.appendChild(fieldRow('Method', methodLabel(meta.deMethod)));\n body.appendChild(fieldRow('Comparison', comparison));\n body.appendChild(fieldRow('Fold-change cutoff', fcLabel));\n body.appendChild(fieldRow('p-value cutoff', pLabel));\n\n const sharerEmail = readSharerEmail(df, meta);\n if (sharerEmail != null) {\n const projectName = df.name || 'shared analysis';\n const mailtoUrl = buildMailtoUrl({\n sharerEmail,\n sharerName: meta.publishedBy || 'colleague',\n projectName,\n publishedDateStr: dateSlice(meta.publishedAt),\n });\n const mailLink = ui.link('Request re-run with different parameters', mailtoUrl);\n (mailLink as HTMLAnchorElement).href = mailtoUrl;\n const mailRow = ui.div([mailLink]);\n mailRow.style.marginTop = '12px';\n body.appendChild(mailRow);\n }\n\n return new DG.Widget(body);\n}\n","/**\n * Dynamic half of the **Proteomics** menu — the analysis groups that need a per-table\n * grey-out, built onto a table view's ribbon.\n *\n * The menu is split across two mechanisms on purpose:\n *\n * - In the **main Datagrok menu (left bar)**: only `Proteomics | Import`, via decorator\n * `top-menu` strings in `package.ts`. This is the always-available entry point,\n * reachable with no table open. The platform owns it — robust, never duplicates.\n * - In a **table view's ribbon**: the full menu (Import + Annotate / Analyze / Visualize\n * / Share), built here onto `view.ribbonMenu`, and ONLY when a Proteomics analysis\n * table is active. The analysis items need `isEnabled` grey-out (a Spectronaut\n * Candidates file has no per-sample intensities, so the sample-level steps don't apply),\n * which only works on a programmatically built menu.\n *\n * The two hosts are independent: a decorator `top-menu` populates `grok.shell.topMenu` (the\n * left-bar menu), NOT `view.ribbonMenu`. When a view's ribbon has its own 'Proteomics'\n * group, the ribbon shows THAT one — so Import has to be (re)added here for the ribbon copy.\n * They don't collide because they live in different menus.\n */\nimport * as DG from 'datagrok-api/dg';\n\n/** Handlers the ribbon menu invokes — including Import, which the ribbon builds itself\n * (the decorator copies only reach the left-bar main menu). Passed in from `package.ts`\n * so this module doesn't import `PackageFunctions` (circular). */\nexport interface ProteomicsMenuHandlers {\n importSpectronautCandidates: () => void;\n importSpectronaut: () => void;\n importMaxQuant: () => void;\n importFragPipe: () => void;\n importGenericMatrix: () => void;\n annotateExperiment: () => void;\n setLog2Scale: () => void;\n normalize: () => void;\n impute: () => void;\n differentialExpression: () => void;\n enrichmentAnalysis: () => void;\n exportEnrichmentInputs: () => void;\n computeSpcStatus: () => void;\n showVolcanoPlot: () => void;\n showHeatmap: () => void;\n showPcaPlot: () => void;\n showGroupMeanCorrelation: () => void;\n showQcDashboard: () => void;\n showSpcDashboard: () => void;\n enrichmentCharts: () => void;\n showAllVisualizations: () => void;\n shareAnalysisForReview: () => void;\n}\n\n/** Our subgroups/items under the ribbon 'Proteomics' group. Cleared before a (re)build so\n * repeated calls replace rather than duplicate. 'Import' is ours here too — the decorator\n * Import lives only in the left-bar main menu, not the ribbon. */\nconst DYNAMIC_SECTIONS = ['Import', 'Annotate Experiment...', 'Analyze', 'Visualize', 'Share'];\n\n/**\n * Is this an analysis table the full Proteomics menu should attach to? Every parser stamps\n * `proteomics.source`, so its presence is the reliable signal. Plain CSVs and the\n * sample-level PCA table (which has no source tag) get only the decorator Import.\n */\nexport function isProteomicsTable(df: DG.DataFrame | null | undefined): boolean {\n return !!df && !!df.getTag('proteomics.source');\n}\n\n/**\n * Disable reason for sample-level menu items on `df`, or `null` when they're fine.\n * Re-evaluated by the platform every time the menu opens, so it tracks the live table.\n * Only a Spectronaut Candidates table is blocked; the per-handler runtime guards stay in\n * place as the backstop for every other not-ready case.\n */\nexport function sampleLevelDisabledReason(df: DG.DataFrame | null | undefined): string | null {\n if (df && df.getTag('proteomics.source') === 'spectronaut-candidates') {\n return 'Not applicable to a Spectronaut Candidates file — it already carries computed ' +\n 'differential expression and has no per-sample intensities. Use Volcano Plot, ' +\n 'Enrichment Analysis or the UniProt panel, or import the matching Spectronaut Report ' +\n 'for sample-level analyses.';\n }\n return null;\n}\n\n/**\n * Build the dynamic analysis groups onto a table view's ribbon, attaching to the Proteomics\n * group the decorator Import created. Returns `true` if it built (the view is a Proteomics\n * table), `false` otherwise — the caller uses that to decide whether the view is \"done\".\n *\n * Idempotent: clears its own sections first (never the decorator 'Import') so a rebuild\n * replaces rather than duplicates.\n */\nexport function buildProteomicsRibbonMenu(view: DG.TableView, h: ProteomicsMenuHandlers): boolean {\n const df = view.dataFrame;\n if (!isProteomicsTable(df))\n return false;\n\n const root = view.ribbonMenu.group('Proteomics');\n for (const s of DYNAMIC_SECTIONS) {\n try { root.remove(s); } catch { /* not present — fine */ }\n }\n\n const sampleOnly = {isEnabled: () => sampleLevelDisabledReason(view.dataFrame)};\n\n // Import — the ribbon's own copy (the decorator Import only reaches the left-bar menu).\n const imp = root.group('Import');\n imp.item('Spectronaut Candidates...', h.importSpectronautCandidates);\n imp.item('Spectronaut Report...', h.importSpectronaut);\n imp.item('MaxQuant...', h.importMaxQuant);\n imp.item('FragPipe...', h.importFragPipe);\n imp.item('Generic Matrix...', h.importGenericMatrix);\n\n root.item('Annotate Experiment...', h.annotateExperiment, null, sampleOnly);\n\n const analyze = root.group('Analyze');\n analyze.item('Set Log2 Scale...', h.setLog2Scale, null, sampleOnly);\n analyze.item('Normalize...', h.normalize, null, sampleOnly);\n analyze.item('Impute Missing Values...', h.impute, null, sampleOnly);\n analyze.item('Differential Expression...', h.differentialExpression, null, sampleOnly);\n analyze.item('Enrichment Analysis...', h.enrichmentAnalysis);\n analyze.item('Export Enrichment Inputs...', h.exportEnrichmentInputs);\n analyze.item('Compute SPC Status', h.computeSpcStatus, null, sampleOnly);\n\n const viz = root.group('Visualize');\n viz.item('Volcano Plot...', h.showVolcanoPlot);\n viz.item('Heatmap...', h.showHeatmap, null, sampleOnly);\n viz.item('PCA...', h.showPcaPlot, null, sampleOnly);\n viz.item('Group-Mean Correlation...', h.showGroupMeanCorrelation, null, sampleOnly);\n viz.item('QC Dashboard...', h.showQcDashboard, null, sampleOnly);\n viz.item('SPC Dashboard...', h.showSpcDashboard);\n viz.item('Enrichment Charts...', h.enrichmentCharts);\n viz.item('Show All Visualizations...', h.showAllVisualizations, null, sampleOnly);\n\n const share = root.group('Share');\n share.item('Share Analysis for Review...', h.shareAnalysisForReview);\n return true;\n}\n","import {PackageFunctions} from './package';\nimport * as DG from 'datagrok-api/dg';\n\n//tags: init\n//meta.role: init\nexport async function initProteomics() : Promise<void> {\n await PackageFunctions.initProteomics();\n}\n\n//tags: autostart\n//meta.autostartImmediate: true\nexport async function buildProteomicsTopMenu() : Promise<void> {\n await PackageFunctions.buildProteomicsTopMenu();\n}\n\n//top-menu: Proteomics | Import | Spectronaut Candidates...\nexport async function importSpectronautCandidates() : Promise<void> {\n await PackageFunctions.importSpectronautCandidates();\n}\n\n//top-menu: Proteomics | Import | Spectronaut Report...\nexport async function importSpectronaut() : Promise<void> {\n await PackageFunctions.importSpectronaut();\n}\n\n//top-menu: Proteomics | Import | MaxQuant...\nexport async function importMaxQuant() : Promise<void> {\n await PackageFunctions.importMaxQuant();\n}\n\n//top-menu: Proteomics | Import | FragPipe...\nexport async function importFragPipe() : Promise<void> {\n await PackageFunctions.importFragPipe();\n}\n\n//top-menu: Proteomics | Import | Generic Matrix...\nexport async function importGenericMatrix() : Promise<void> {\n await PackageFunctions.importGenericMatrix();\n}\n\n//name: annotateExperiment\nexport async function annotateExperiment() : Promise<void> {\n await PackageFunctions.annotateExperiment();\n}\n\n//name: setLog2Scale\nexport async function setLog2Scale() : Promise<void> {\n await PackageFunctions.setLog2Scale();\n}\n\n//name: normalizeProteomics\nexport async function normalizeProteomics() : Promise<void> {\n await PackageFunctions.normalizeProteomics();\n}\n\n//name: imputeMissingValues\nexport async function imputeMissingValues() : Promise<void> {\n await PackageFunctions.imputeMissingValues();\n}\n\n//name: differentialExpression\nexport async function differentialExpression() : Promise<void> {\n await PackageFunctions.differentialExpression();\n}\n\n//name: computeSpcStatus\nexport async function computeSpcStatus() : Promise<void> {\n await PackageFunctions.computeSpcStatus();\n}\n\n//name: showVolcanoPlot\nexport async function showVolcanoPlot() : Promise<void> {\n await PackageFunctions.showVolcanoPlot();\n}\n\n//name: showHeatmap\nexport async function showHeatmap() : Promise<void> {\n await PackageFunctions.showHeatmap();\n}\n\n//name: showPcaPlot\nexport async function showPcaPlot() : Promise<void> {\n await PackageFunctions.showPcaPlot();\n}\n\n//name: showGroupMeanCorrelation\nexport async function showGroupMeanCorrelation() : Promise<void> {\n await PackageFunctions.showGroupMeanCorrelation();\n}\n\n//name: showQcDashboard\nexport async function showQcDashboard() : Promise<void> {\n await PackageFunctions.showQcDashboard();\n}\n\n//name: showSpcDashboard\nexport async function showSpcDashboard() : Promise<void> {\n await PackageFunctions.showSpcDashboard();\n}\n\n//name: showAllVisualizations\nexport async function showAllVisualizations() : Promise<void> {\n await PackageFunctions.showAllVisualizations();\n}\n\n//name: enrichmentAnalysis\nexport async function enrichmentAnalysis() : Promise<void> {\n await PackageFunctions.enrichmentAnalysis();\n}\n\n//name: exportEnrichmentInputs\nexport async function exportEnrichmentInputs() : Promise<void> {\n await PackageFunctions.exportEnrichmentInputs();\n}\n\n//name: enrichmentCharts\nexport async function enrichmentCharts() : Promise<void> {\n await PackageFunctions.enrichmentCharts();\n}\n\n//name: Proteomics Demo\n//meta.demoPath: Proteomics | Differential Expression\n//meta.isDemoDashboard: true\nexport async function proteomicsDemo() : Promise<void> {\n await PackageFunctions.proteomicsDemo();\n}\n\n//name: Proteomics Enrichment Demo\n//meta.demoPath: Proteomics | Enrichment Analysis\n//meta.isDemoDashboard: true\nexport async function proteomicsEnrichmentDemo() : Promise<void> {\n await PackageFunctions.proteomicsEnrichmentDemo();\n}\n\n//name: Proteomics | UniProt\n//description: UniProt protein details\n//input: string proteinId { semType: Proteomics-ProteinId }\n//output: widget result\n//meta.role: widgets,panel\nexport function uniprotPanelWidget(proteinId: string) : any {\n return PackageFunctions.uniprotPanelWidget(proteinId);\n}\n\n//name: shareAnalysisForReview\nexport async function shareAnalysisForReview() : Promise<void> {\n await PackageFunctions.shareAnalysisForReview();\n}\n\n//name: Proteomics | Shared Analysis\n//description: Audit context for a shared analysis snapshot\n//input: string proteinId { semType: Proteomics-ProteinId }\n//output: widget result\n//meta.role: widgets,panel\nexport function publishedAnalysisPanelWidget(proteinId: string) : any {\n return PackageFunctions.publishedAnalysisPanelWidget(proteinId);\n}\n\n//tags: autostart\n//meta.autostartImmediate: true\nexport async function recoverPublishedProjectsOnStartup() : Promise<void> {\n await PackageFunctions.recoverPublishedProjectsOnStartup();\n}\n","/* Do not change these import lines. Datagrok will import API library in exactly the same manner */\nimport * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\nimport * as rxjs from 'rxjs';\nimport {debounceTime} from 'rxjs/operators';\n\nimport {parseMaxQuantText} from './parsers/maxquant-parser';\nimport {parseSpectronautText, parseSpectronautStream} from './parsers/spectronaut-parser';\nimport {parseSpectronautCandidatesText, COMPARISON_COLUMNS}\n from './parsers/spectronaut-candidates-parser';\nimport {parseFragPipeText} from './parsers/fragpipe-parser';\nimport {showGenericImportDialog} from './parsers/generic-parser';\nimport {showAnnotationDialog, getGroups, getOrganism, setOrganism} from './analysis/experiment-setup';\nimport {detectOrganismCode} from './utils/organisms';\nimport {computeSpcMetrics, evaluateNelsonRulesAllMetrics, setSpcStatus, getRunMeta,\n defaultRulesEnabledAllMetrics, BaselineSnapshot} from './analysis/spc';\nimport {upsertRun, loadRuns, loadBaseline, SpcRunRow} from './analysis/spc-storage';\nimport {showNormalizationDialog, quantileNormalize, vsnNormalize} from './analysis/normalization';\nimport {showLog2ScaleDialog} from './analysis/log2-scale';\nimport {showEnrichmentInputExportDialog} from './analysis/enrichment-export';\nimport {showImputationDialog, imputeKnn, imputeZero, imputeMean, imputeMedian} from './analysis/imputation';\nimport {showDEDialog, requireDifferentialExpression} from './analysis/differential-expression';\nimport {createVolcanoPlot, recomputeVolcano, readVolcanoState, MetricKind, applyTopNLabels,\n getVolcanoTopN, showVolcanoBusy, updateVolcanoBusy, hideVolcanoBusy,\n getVolcanoAxisMax, setVolcanoAxisMax,\n LOCATION_COL} from './viewers/volcano';\nimport {STORE as SUBCELL_STORE} from './analysis/subcellular-location';\nimport {createExpressionHeatmap} from './viewers/heatmap';\nimport {createPcaPlot} from './viewers/pca-plot';\nimport {openQcDashboard} from './viewers/qc-dashboard';\nimport {openSpcDashboard} from './viewers/spc-dashboard';\nimport {createGroupMeanCorrelation} from './viewers/group-mean-correlation';\nimport {uniprotPanel} from './panels/uniprot-panel';\nimport {focusProtein} from './panels/protein-focus';\nimport {publishedAnalysisPanel} from './panels/published-analysis-panel';\nimport {showShareForReviewDialog} from './publishing/share-dialog';\nimport {recoverPublishedProject} from './publishing/post-open-recovery';\nimport {isPublished} from './publishing/publish-state';\nimport {showEnrichmentDialog} from './analysis/enrichment';\nimport {openEnrichmentVisualization} from './viewers/enrichment-viewers';\nimport {findColumn} from './utils/column-detection';\nimport {SEMTYPE, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from './utils/proteomics-types';\nimport {buildProteomicsRibbonMenu} from './menu';\nimport {runProteomicsDemo} from './demo/proteomics-demo';\nimport {runEnrichmentDemo} from './demo/enrichment-demo';\n\nexport const _package = new DG.Package();\nexport * from './package.g';\n\n/** Temporary polyfill */\n\nfunction getDecoratorFunc() {\n return function(args: any) {\n return function(\n target: any,\n propertyKey: string,\n descriptor: PropertyDescriptor,\n ) { };\n };\n}\n\nif (!grok.decorators)\n (grok as any).decorators = {};\n\nconst decorators = [\n 'func', 'init', 'param', 'panel', 'editor', 'demo', 'app',\n 'appTreeBrowser', 'fileHandler', 'fileExporter', 'model', 'viewer', 'filter', 'cellRenderer', 'autostart',\n 'dashboard', 'folderViewer', 'semTypeDetector', 'packageSettingsEditor', 'functionAnalysis', 'converter',\n 'fileViewer', 'treeBrowser', 'polyfill',\n];\n\ndecorators.forEach((decorator) => {\n if (!(grok.decorators as any)[decorator])\n (grok.decorators as any)[decorator] = getDecoratorFunc();\n});\n\n/** End temporary polyfill */\n\n\n/** Guard for menu handlers that operate on per-sample intensity data. Returns\n * false (with a clear warning) when the open DataFrame is a pre-computed DE\n * output like a Spectronaut Candidates report — those have no per-sample\n * intensity columns, no group annotations, and no raw quantification to feed\n * into Annotate / Normalize / Impute / DE / Heatmap / PCA / QC. */\nfunction requireSampleLevelData(df: DG.DataFrame, action: string): boolean {\n const source = df.getTag('proteomics.source');\n if (source === 'spectronaut-candidates') {\n grok.shell.warning(\n `${action} needs per-sample intensities, but this table is a Spectronaut Candidates ` +\n `report (one row per protein per comparison — pre-computed DE only). ` +\n `Import the matching Spectronaut Report (Proteomics | Import | Spectronaut Report) ` +\n `to enable per-sample analyses, or stick to Volcano / Enrichment / UniProt panel on this one.`,\n );\n return false;\n }\n return true;\n}\n\n\n/** Precursor/fragment-level signature columns. A Spectronaut report carrying\n * any of these is a long-format precursor export that must go through the\n * streaming aggregator (the V8 string ceiling makes file.text() OOM on the\n * 2.6 GB real report). A PG-level long report has none of these and keeps the\n * proven file.text() path. */\nconst PRECURSOR_SIGNATURE_COLUMNS = ['EG.ModifiedPeptide', 'FG.Charge', 'PEP.StrippedSequence'];\n\n/** D-01 header sniff: streams only until the first newline (with a ~1 MB sanity\n * guard), then cancels the reader to release the stream — the rest of the file\n * is never read here. Returns true iff the header carries a precursor signature\n * column, in which case `importSpectronaut` routes to `parseSpectronautStream`. */\nexport async function sniffIsPrecursor(file: File): Promise<boolean> {\n const reader = file.stream()\n .pipeThrough(new TextDecoderStream('utf-8'))\n .getReader();\n try {\n let buffer = '';\n const maxBytes = 1024 * 1024; // 1 MB pre-newline sanity guard\n while (buffer.indexOf('\\n') < 0 && buffer.length < maxBytes) {\n const {value, done} = await reader.read();\n if (done) break;\n buffer += value;\n }\n const nl = buffer.indexOf('\\n');\n let header = nl >= 0 ? buffer.slice(0, nl) : buffer;\n if (header.endsWith('\\r')) header = header.slice(0, -1);\n return PRECURSOR_SIGNATURE_COLUMNS.some((c) => header.includes(c));\n } finally {\n await reader.cancel();\n }\n}\n\n\n/** Module-level subscription store for the unified Filters viewer's\n * search-match → df.selection wiring. Disposed on re-entry so a second\n * multi-contrast import does not leak the prior handler. */\nlet activeFilterSubscriptions: rxjs.Subscription[] = [];\n\n/** Sets `proteomics.organism` from the data's organism column at import when it\n * resolves to a single supported species, so enrichment and the subcellular-\n * location fetch narrow to the right organism without waiting for a dialog.\n * No-op when already set, absent, or ambiguous (multi-species) — the user then\n * picks in the Annotate/Enrichment dialog. */\nfunction autoDetectOrganism(df: DG.DataFrame): void {\n if (getOrganism(df)) return;\n const code = detectOrganismCode(df);\n if (code) setOrganism(df, code);\n}\n\n/**\n * R4/D-07 + G4 + D-05: when a Spectronaut Candidates file carries more than one\n * distinct Comparison, dock a native Datagrok Filters viewer carrying typed\n * per-column filters: a categorical filter on Comparison plus free-text search\n * boxes on Display Name and Source ID (D-05 unified protein search). A single\n * distinct comparison docks nothing. Shell-only orchestration — the parser\n * stays pure. Returns whether a filter was docked.\n *\n * G4 root-cause fix (14-RESEARCH.md §\"Pattern 1\" / §\"Pitfall 1\"):\n * Phase 13 observed that the `columnNames` allowlist silently extends itself\n * with the boolean `Flags` column via the combined-boolean filter. We migrate\n * to the typed `filters` array and set `showBoolCombinedFilter: false` to\n * exclude Flags explicitly. A runtime verification gate falls back to an\n * explicit setOptions() override if the platform still leaks Flags into the\n * look config.\n */\nexport function dockComparisonFilterIfMultiContrast(\n tv: DG.TableView, df: DG.DataFrame,\n): boolean {\n const cmpCol = COMPARISON_COLUMNS.reduce<DG.Column | null>(\n (found, name) => found ?? df.col(name), null);\n if (!cmpCol) return false;\n const distinct = new Set<string>();\n for (let i = 0; i < df.rowCount; i++) {\n const v = cmpCol.get(i);\n if (typeof v === 'string' && v.length > 0) distinct.add(v);\n }\n if (distinct.size <= 1) return false;\n\n // Display Name + Source ID come from Plan 14-01's gene-label resolver. On\n // DataFrames predating Plan 01 the columns may be absent — fall back to the\n // Protein ID column so the search-by-gene affordance still works.\n const displayNameCol = findColumn(df, SEMTYPE.DISPLAY_NAME, ['display name']);\n const sourceIdCol = findColumn(df, SEMTYPE.SOURCE_ID, ['source id']);\n const proteinIdCol = findColumn(df, SEMTYPE.PROTEIN_ID,\n ['primary protein id', 'protein id', 'uniprot', 'accession']);\n\n // Live UAT (2026-06-04) found the typed `filters: filterSpecs` shape doesn't\n // round-trip through the platform serializer — getOptions().look ends up\n // with ONLY `showBoolCombinedFilter`, no `filters` or `columnNames`, so the\n // viewer docks empty. The legacy `columnNames` array shape is the stable\n // contract: it materializes the requested columns as categorical filters\n // (free-text/categorical type is inferred per column). Display Name +\n // Source ID become string-categorical filters that include a search box\n // each — they replace the typed free-text filters with no UX regression.\n const columnNames: string[] = [cmpCol.name];\n if (displayNameCol) columnNames.push(displayNameCol.name);\n if (sourceIdCol) columnNames.push(sourceIdCol.name);\n if (!displayNameCol && proteinIdCol) columnNames.push(proteinIdCol.name);\n\n const filters = DG.Viewer.filters(df, {\n columnNames,\n showBoolCombinedFilter: false, // G4 Flags exclusion (14-RESEARCH §\"Pitfall 1\")\n showHeader: true,\n showSearchBox: true,\n } as any);\n\n tv.dockManager.dock(filters, DG.DOCK_TYPE.RIGHT, null, 'Filters', 0.3);\n\n // D-05 search-match wiring: free-text search boxes on Display Name / Source ID\n // mutate df.filter (hide non-matching rows). UI-SPEC requires highlight-not-\n // hide so the NS cloud stays visible. Defensive capture-restore path per\n // 14-RESEARCH §\"Open Q 1 (RESOLVED)\":\n // 1. Save df.filter into savedBitSet before subscribing.\n // 2. On df.onFilterChanged (debounced): capture matched indices from the\n // current (search-mutated) df.filter.\n // 3. Restore df.filter via copyFrom(savedBitSet) so non-matched rows\n // stay visible.\n // 4. Write df.selection.set(idx) on the matched indices.\n // 5. applyTopNLabels(df, sp, N, matched) so the top-N labels coexist with\n // the search-matched rows (Pitfall 7). Labels are decoupled from\n // selection — step 4's selection is the search highlight only.\n // The `restoring` flag guards re-entry from the copyFrom step.\n // Assumption A5: df.selection.set does NOT re-trigger df.filter.onChanged.\n for (const s of activeFilterSubscriptions) s.unsubscribe();\n activeFilterSubscriptions = [];\n\n const findVolcano = (): DG.ScatterPlotViewer | null => {\n for (const v of tv.viewers) {\n if (v.type === DG.VIEWER.SCATTER_PLOT &&\n (v as DG.ScatterPlotViewer).props.yColumnName === 'negLog10P')\n return v as DG.ScatterPlotViewer;\n }\n return null;\n };\n\n const savedBitSet = DG.BitSet.create(df.rowCount);\n savedBitSet.copyFrom(df.filter);\n let restoring = false;\n\n activeFilterSubscriptions.push(df.onFilterChanged.pipe(debounceTime(100)).subscribe(() => {\n if (restoring) return; // guard against the restore call re-triggering this handler\n\n // Capture matched indices from the current (search-mutated) df.filter.\n const matched: number[] = [];\n for (let i = 0; i < df.rowCount; i++) {\n if (df.filter.get(i)) matched.push(i);\n }\n\n // If nothing was filtered out (filter equals saved state), the change came\n // from elsewhere — nothing to highlight, just refresh the saved state.\n if (matched.length === df.rowCount) {\n savedBitSet.copyFrom(df.filter);\n return;\n }\n\n // Restore df.filter to its pre-search state.\n restoring = true;\n try {\n df.filter.copyFrom(savedBitSet);\n } finally {\n restoring = false;\n }\n\n // Write df.selection from the match (Assumption A5: no onFilterChanged re-trigger).\n df.selection.setAll(false, false);\n for (const idx of matched) df.selection.set(idx, true, false);\n df.selection.fireChanged();\n\n // Pitfall 7: the top-N labels must coexist with the search match. Labels\n // are decoupled from selection now, so label the top-N PLUS the matched\n // rows (the matched rows also stay highlighted via the selection above).\n const sp = findVolcano();\n if (sp) applyTopNLabels(df, sp, getVolcanoTopN(df), matched);\n }));\n\n return true;\n}\n\n/**\n * Opens the standard Candidates analysis view: table view, auto-volcano,\n * multi-contrast comparison filter, and protein focus. Extracted from the\n * import handler so the auto-volcano behavior is testable without the file\n * dialog. Returns the created TableView.\n *\n * The volcano is opened HERE because Candidates arrive with the DE result\n * already computed (the parser sets `proteomics.de_complete`), so the pipeline's\n * DE step — where the Report path auto-opens the volcano — never runs. Opening\n * it here lands both entry points on the same primary deliverable. Best-effort:\n * skip silently if the volcano's columns are somehow absent, exactly as the\n * DE-completion path tolerates.\n */\nexport function openCandidatesAnalysisView(df: DG.DataFrame): DG.TableView {\n const tv = grok.shell.addTableView(df);\n grok.shell.info(`Imported ${df.rowCount} candidates from Spectronaut`);\n try {\n tv.addViewer(createVolcanoPlot(df));\n } catch (volcanoErr: any) {\n grok.shell.warning(\n `Imported, but could not auto-open the volcano: ${volcanoErr?.message ?? volcanoErr}. ` +\n `Open it via Proteomics | Visualize | Volcano Plot.`);\n }\n dockComparisonFilterIfMultiContrast(tv, df);\n focusProtein(df);\n return tv;\n}\n\nexport class PackageFunctions {\n @grok.decorators.init({tags: ['init']})\n static async initProteomics(): Promise<void> {\n }\n\n /**\n * Adds the dynamic Proteomics analysis groups (Annotate / Analyze / Visualize / Share)\n * to a table view's ribbon — see `src/menu.ts`. Import is NOT here; it is a decorator\n * `top-menu` (above) so the platform keeps it in the main left-bar menu and on every\n * ribbon. These groups need `isEnabled` grey-out, which only works on a programmatic\n * menu, so we build them onto the SAME ribbon 'Proteomics' group (get-or-create) the\n * decorator Import created — but only for tables that actually hold Proteomics data.\n *\n * Built once per view (tracked in `done`): `isEnabled` re-evaluates on every menu open,\n * so there is no need to rebuild on view activation — which is what caused the earlier\n * duplicate-menu bug. A view whose table isn't yet a Proteomics table (builder returns\n * false) is left untracked so a later activation retries.\n */\n @grok.decorators.func({tags: ['autostart'], meta: {autostartImmediate: 'true'}})\n static async buildProteomicsTopMenu(): Promise<void> {\n const handlers = {\n importSpectronautCandidates: () => PackageFunctions.importSpectronautCandidates(),\n importSpectronaut: () => PackageFunctions.importSpectronaut(),\n importMaxQuant: () => PackageFunctions.importMaxQuant(),\n importFragPipe: () => PackageFunctions.importFragPipe(),\n importGenericMatrix: () => PackageFunctions.importGenericMatrix(),\n annotateExperiment: () => PackageFunctions.annotateExperiment(),\n setLog2Scale: () => PackageFunctions.setLog2Scale(),\n normalize: () => PackageFunctions.normalizeProteomics(),\n impute: () => PackageFunctions.imputeMissingValues(),\n differentialExpression: () => PackageFunctions.differentialExpression(),\n enrichmentAnalysis: () => PackageFunctions.enrichmentAnalysis(),\n exportEnrichmentInputs: () => PackageFunctions.exportEnrichmentInputs(),\n computeSpcStatus: () => PackageFunctions.computeSpcStatus(),\n showVolcanoPlot: () => PackageFunctions.showVolcanoPlot(),\n showHeatmap: () => PackageFunctions.showHeatmap(),\n showPcaPlot: () => PackageFunctions.showPcaPlot(),\n showGroupMeanCorrelation: () => PackageFunctions.showGroupMeanCorrelation(),\n showQcDashboard: () => PackageFunctions.showQcDashboard(),\n showSpcDashboard: () => PackageFunctions.showSpcDashboard(),\n enrichmentCharts: () => PackageFunctions.enrichmentCharts(),\n showAllVisualizations: () => PackageFunctions.showAllVisualizations(),\n shareAnalysisForReview: () => PackageFunctions.shareAnalysisForReview(),\n };\n\n const done = new WeakSet<object>();\n const ensure = (view: any): void => {\n if (view?.type !== DG.VIEW_TYPE.TABLE_VIEW || done.has(view)) return;\n // Defer so the platform has built the decorator Import into the ribbon's Proteomics\n // group first; our get-or-create then attaches to it instead of racing a duplicate.\n setTimeout(() => {\n if (done.has(view)) return;\n try {\n if (buildProteomicsRibbonMenu(view as DG.TableView, handlers))\n done.add(view);\n } catch { /* ribbon not ready — a later activation retries */ }\n }, 50);\n };\n\n try { for (const v of grok.shell.views) ensure(v); } catch { /* no views yet */ }\n grok.events.onViewAdded.subscribe(ensure);\n grok.events.onCurrentViewChanged.subscribe(() => ensure(grok.shell.v));\n }\n\n // Import lives on decorator `top-menu` (not the dynamic ribbon builder) so it shows in\n // the main Datagrok menu (left bar) as an always-available entry point. Declaration\n // order sets menu order: Candidates first, then Report, then the rest.\n @grok.decorators.func({'top-menu': 'Proteomics | Import | Spectronaut Candidates...'})\n static async importSpectronautCandidates(): Promise<void> {\n DG.Utils.openFile({\n accept: '.tsv,.txt,.csv',\n open: async (file: File) => {\n try {\n const text = await file.text();\n const df = await parseSpectronautCandidatesText(text);\n df.name = file.name.replace(/\\.[^.]+$/, '');\n autoDetectOrganism(df);\n openCandidatesAnalysisView(df);\n } catch (e: any) {\n grok.shell.error(`Failed to import Spectronaut Candidates file: ${e?.message ?? e}`);\n }\n },\n });\n }\n\n @grok.decorators.func({'top-menu': 'Proteomics | Import | Spectronaut Report...'})\n static async importSpectronaut(): Promise<void> {\n DG.Utils.openFile({\n accept: '.tsv,.txt,.csv',\n open: async (file: File) => {\n try {\n const df = (await sniffIsPrecursor(file)) ?\n await parseSpectronautStream(file) : await parseSpectronautText(await file.text());\n df.name = file.name.replace(/\\.[^.]+$/, '');\n autoDetectOrganism(df);\n grok.shell.addTableView(df);\n grok.shell.info(`Imported ${df.rowCount} protein groups from Spectronaut`);\n focusProtein(df);\n } catch (e: any) {\n grok.shell.error(`Failed to import Spectronaut file: ${e?.message ?? e}`);\n grok.shell.warning(\n `If this is a very large precursor-level Spectronaut report that fails to ` +\n `stream in-browser, pre-aggregate it to the importable protein-group shape ` +\n `with the bundled duckdb fallback: tools/spectronaut-aggregate.sh <input.tsv>, ` +\n `then re-import the resulting file. See files/demo/README.md for usage.`,\n );\n }\n },\n });\n }\n\n @grok.decorators.func({'top-menu': 'Proteomics | Import | MaxQuant...'})\n static async importMaxQuant(): Promise<void> {\n DG.Utils.openFile({\n accept: '.txt,.tsv',\n open: async (file: File) => {\n try {\n const text = await file.text();\n const df = await parseMaxQuantText(text);\n df.name = file.name.replace(/\\.[^.]+$/, '');\n autoDetectOrganism(df);\n grok.shell.addTableView(df);\n grok.shell.info(`Imported ${df.rowCount} protein groups`);\n focusProtein(df);\n } catch (e: any) {\n grok.shell.error(`Failed to import MaxQuant file: ${e?.message ?? e}`);\n }\n },\n });\n }\n\n @grok.decorators.func({'top-menu': 'Proteomics | Import | FragPipe...'})\n static async importFragPipe(): Promise<void> {\n DG.Utils.openFile({\n accept: '.tsv,.txt',\n open: async (file: File) => {\n try {\n const text = await file.text();\n const df = await parseFragPipeText(text);\n df.name = file.name.replace(/\\.[^.]+$/, '');\n autoDetectOrganism(df);\n grok.shell.addTableView(df);\n grok.shell.info(`Imported ${df.rowCount} protein groups from FragPipe`);\n focusProtein(df);\n } catch (e: any) {\n grok.shell.error(`Failed to import FragPipe file: ${e?.message ?? e}`);\n }\n },\n });\n }\n\n @grok.decorators.func({'top-menu': 'Proteomics | Import | Generic Matrix...'})\n static async importGenericMatrix(): Promise<void> {\n showGenericImportDialog();\n }\n\n @grok.decorators.func()\n static async annotateExperiment(): Promise<void> {\n const df = grok.shell.tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Annotate Experiment')) return;\n showAnnotationDialog(df);\n }\n\n @grok.decorators.func()\n static async setLog2Scale(): Promise<void> {\n const df = grok.shell.tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Set Log2 Scale')) return;\n showLog2ScaleDialog(df);\n }\n\n @grok.decorators.func()\n static async normalizeProteomics(): Promise<void> {\n const df = grok.shell.tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Normalize')) return;\n showNormalizationDialog(df);\n }\n\n @grok.decorators.func()\n static async imputeMissingValues(): Promise<void> {\n const df = grok.shell.tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Impute Missing Values')) return;\n showImputationDialog(df);\n }\n\n @grok.decorators.func()\n static async differentialExpression(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Differential Expression')) return;\n showDEDialog(df, () => {\n // Auto-open volcano plot after DE completes. Title is synthesized by\n // createVolcanoPlot from proteomics.groups per the G1 contract.\n const sp = createVolcanoPlot(df);\n tv.addViewer(sp);\n });\n }\n\n @grok.decorators.func()\n static async computeSpcStatus(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) {\n grok.shell.warning('Open an analyzed file first, then run Compute SPC Status.');\n return;\n }\n if (df.getTag('proteomics.source') === 'spectronaut-candidates') {\n grok.shell.warning('SPC requires per-sample intensities. Re-import this analysis ' +\n 'from the Spectronaut PG report (not the Candidates report) to compute SPC.');\n return;\n }\n const runMeta = getRunMeta(df);\n if (!runMeta || !runMeta.instrument_id || !runMeta.acquisition_datetime) {\n grok.shell.warning('Open Annotate Experiment to set instrument + acquisition datetime.');\n return;\n }\n const groups = getGroups(df);\n if (!groups) {\n grok.shell.warning('Annotate experimental groups first (Proteomics → Annotate Experiment) ' +\n '— SPC needs Group 1 to compute control-replicate correlation.');\n return;\n }\n if (groups.group1.columns.length < 2) {\n grok.shell.info(\"Group 1 has fewer than 2 samples — control-replicate correlation can't \" +\n 'be computed. The other three metrics will still be recorded.');\n }\n\n const pi = DG.TaskBarProgressIndicator.create('Computing SPC status...');\n try {\n const metrics = computeSpcMetrics(df, groups, runMeta);\n const baseline = await loadBaseline(runMeta.instrument_id);\n const priorRuns = await loadRuns(runMeta.instrument_id);\n const priorRow = priorRuns.find((r) =>\n r.acquisition_datetime === runMeta.acquisition_datetime);\n const priorStatus = priorRow?.status ?? null;\n\n let ruleResult: {status: 'pass' | 'flagged' | 'out_of_control'; rulesTripped: string[]};\n if (baseline === null) {\n ruleResult = {status: 'pass', rulesTripped: []};\n grok.shell.info(`No baseline locked for ${runMeta.instrument_id} yet — recorded as pass. ` +\n 'Define a baseline once at least 4 runs have been computed.');\n } else {\n const priorSeries = {\n median_intensity: priorRuns.map((r) => r.median_intensity),\n missing_pct: priorRuns.map((r) => r.missing_pct),\n control_corr: priorRuns.map((r) => r.control_corr),\n protein_count: priorRuns.map((r) => r.protein_count),\n };\n ruleResult = evaluateNelsonRulesAllMetrics(\n metrics, priorSeries,\n baseline.metrics as BaselineSnapshot,\n baseline.rules_enabled ?? defaultRulesEnabledAllMetrics(),\n );\n }\n\n setSpcStatus(df, metrics, ruleResult);\n\n const row: Omit<SpcRunRow, 'run_id'> & {run_id?: string} = {\n instrument_id: runMeta.instrument_id,\n acquisition_datetime: runMeta.acquisition_datetime,\n run_label: df.name,\n median_intensity: metrics.median_intensity,\n missing_pct: metrics.missing_pct,\n control_corr: metrics.control_corr,\n protein_count: metrics.protein_count,\n status: ruleResult.status,\n rules_tripped: ruleResult.rulesTripped,\n source_project_id: null,\n source_df_name: df.name,\n computed_at: metrics.computed_at,\n };\n await upsertRun(row);\n\n if (priorStatus !== null)\n grok.shell.info(`Updated SPC for ${df.name} (previous status: ${priorStatus}).`);\n else if (ruleResult.status === 'pass')\n grok.shell.info(`SPC computed: ${df.name} — status: pass.`);\n else if (ruleResult.status === 'flagged')\n grok.shell.info(`SPC computed: ${df.name} — flagged on ${ruleResult.rulesTripped.length} ` +\n `rule(s): ${ruleResult.rulesTripped.join(', ')}.`);\n else\n grok.shell.info(`SPC computed: ${df.name} — OUT OF CONTROL on ` +\n `${ruleResult.rulesTripped.length} rule(s): ${ruleResult.rulesTripped.join(', ')}.`);\n } finally {\n pi.close();\n }\n }\n\n @grok.decorators.func()\n static async showVolcanoPlot(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireDifferentialExpression(df,\n 'Run Differential Expression first (Proteomics | Analyze | Differential Expression)')) return;\n\n // Single menu item: open the options dialog. It reconfigures an existing\n // volcano, or — when none exists yet — CREATES it on OK (so nothing is\n // drawn until the user confirms; Cancel draws nothing). The old separate\n // 'Volcano Options...' item is folded in here.\n await PackageFunctions.volcanoOptions();\n }\n\n /** Volcano Plot options dialog. No longer its own menu item — showVolcanoPlot\n * delegates here. Reconfigures the existing volcano, or creates one on OK when\n * none exists. `spArg` is an already-resolved viewer (skips the lookup). */\n static async volcanoOptions(spArg?: DG.ScatterPlotViewer): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireDifferentialExpression(df,\n 'Run Differential Expression first (Proteomics | Analyze | Differential Expression)')) return;\n\n // The volcano is the scatter plot whose Y is the -log10(metric) column.\n // It may NOT exist yet — in that case sp stays undefined and the OK handler\n // creates it, so the plot is only drawn once the user confirms.\n let sp: DG.ScatterPlotViewer | undefined = spArg;\n if (!sp) {\n for (const v of tv.viewers) {\n if (v.type === DG.VIEWER.SCATTER_PLOT &&\n (v as DG.ScatterPlotViewer).props.yColumnName === 'negLog10P') {\n sp = v as DG.ScatterPlotViewer;\n break;\n }\n }\n }\n\n // G2 dialog-state preload: snapshot current viewer state at open time and\n // seed every input from it. Pitfall 2 — getOptions is a snapshot, not a\n // live binding; OK uses the input values, never a re-read. With no existing\n // plot, seed from defaults.\n const state: {metric: MetricKind; colorDim: 'significance' | 'location'} = sp ?\n readVolcanoState(df, sp) : {metric: 'adj.p-value', colorDim: 'significance'};\n const hasPValue = df.col('p-value') != null;\n const initialMetric: MetricKind =\n hasPValue ? state.metric : 'adj.p-value';\n const metricInput = ui.input.choice('Significance metric', {\n value: initialMetric,\n items: hasPValue ? ['adj.p-value', 'p-value'] : ['adj.p-value'],\n nullable: false,\n });\n metricInput.setTooltip(hasPValue ?\n 'Y axis, classification and threshold line all switch together' :\n 'p-value column not present — only adj.p-value is available');\n const colorInput = ui.input.choice('Color by', {\n value: state.colorDim,\n items: ['significance', 'location'],\n nullable: false,\n });\n colorInput.setTooltip(\n 'significance = Enriched in g1 / Enriched in g2 / Not significant; ' +\n 'location = UniProt subcellular location');\n const labelTopNInput = ui.input.int('Label top N points', {\n value: getVolcanoTopN(df),\n min: 0,\n });\n labelTopNInput.setTooltip(\n 'How many of the most significant proteins get name labels. 0 = none. ' +\n 'Labels no longer touch your row selection.');\n\n // Optional axis-max overrides so volcanoes from different contrasts can be\n // pinned to a shared scale and compared side-by-side. Empty = auto-scale.\n const axis = getVolcanoAxisMax(df);\n const xMaxInput = ui.input.float('X-axis max (|log2FC|)', {\n value: axis.xMax ?? undefined,\n min: 0,\n nullable: true,\n });\n xMaxInput.setTooltip(\n 'Pin the X axis to ±this |log2FC|. Leave empty to auto-scale. ' +\n 'Set the same value on two volcanoes to compare them side-by-side.');\n const yMaxInput = ui.input.float('Y-axis max (−log10 p)', {\n value: axis.yMax ?? undefined,\n min: 0,\n nullable: true,\n });\n yMaxInput.setTooltip(\n 'Pin the Y axis to 0…this −log10(p). Leave empty to auto-scale. ' +\n 'Set the same value on two volcanoes to compare them side-by-side.');\n\n ui.dialog('Volcano Options')\n .add(metricInput)\n .add(colorInput)\n .add(labelTopNInput)\n .add(xMaxInput)\n .add(yMaxInput)\n .onOK(async () => {\n const metric = (metricInput.value ?? 'adj.p-value') as MetricKind;\n const colorDim = colorInput.value === 'location' ? 'location' : 'significance';\n\n // Persist the axis-max overrides before recompute — recomputeVolcano\n // ends with applyVolcanoAxisBounds, which reads these tags back.\n setVolcanoAxisMax(df, xMaxInput.value ?? null, yMaxInput.value ?? null);\n\n // First-time path: create the volcano NOW (on OK), so it isn't drawn\n // until the user confirms. topNLabels=0 here — applyTopNLabels below\n // sets the chosen count after the metric/color recompute.\n if (!sp) {\n sp = createVolcanoPlot(df, {topNLabels: 0});\n tv.addViewer(sp);\n }\n\n // Cache-aware pre-OK toast — the column-present path is sub-second\n // (short-circuit in ensureLocationColumn) so no toast is needed; the\n // column-absent + cold-cache path takes 30-90 s on a real Spectronaut\n // file and the user deserves a heads-up; the column-absent + warm-cache\n // path is a few seconds at most and deserves a shorter toast.\n if (colorDim === 'location' && !df.col(LOCATION_COL)) {\n const cache = await grok.dapi.userDataStorage.get(SUBCELL_STORE).catch(() => null);\n const cacheEntryCount = cache ?\n Object.keys(cache).filter((k) => k !== '__schema_v').length : 0;\n if (cacheEntryCount === 0) {\n grok.shell.info(\n 'Fetching subcellular locations from UniProt — may take a minute or two ' +\n 'on first use without cache; subsequent toggles use the cache.');\n } else {\n grok.shell.info('Resolving subcellular locations from cache.');\n }\n }\n\n // G3 wording: progress label is color-specific so a slow Color =\n // Location click reads as classification work, not generic \"updating\".\n const initialLabel = colorDim === 'location' ?\n 'Classifying subcellular locations…' : 'Updating volcano…';\n const pi = DG.TaskBarProgressIndicator.create(initialLabel);\n\n // 13-10: also show progress on the volcano viewer itself — the\n // TaskBarProgressIndicator at the bottom of the platform shell is too\n // easy to miss while staring at a stale-looking chart. Attach when the\n // recompute can actually fetch from UniProt (colorDim === 'location').\n // On the 13-08 warm-cache short-circuit the overlay either flashes for\n // a single frame or appears very briefly; hideVolcanoBusy in finally\n // cleans up either way.\n const willFetchLocation = colorDim === 'location';\n if (willFetchLocation) showVolcanoBusy(sp!, initialLabel);\n\n // Map ProgressCb phases onto a human-readable pi.update label.\n const progress = (done: number, total: number, phase: string) => {\n const label = phase === 'fetch-acc' ? 'Fetching subcellular locations' :\n phase === 'fetch-gene' ? 'Resolving by gene name' :\n phase === 'init-column' ? 'Classifying subcellular locations' :\n colorDim === 'location' ? 'Classifying subcellular locations' :\n 'Updating volcano';\n const pct = total > 0 ? Math.round((done / total) * 100) : 0;\n pi.update(pct, `${label}: ${done}/${total}`);\n if (willFetchLocation) {\n const detail = total > 1 ? `${done}/${total} (${pct}%)` : '';\n updateVolcanoBusy(sp!, label, detail);\n }\n };\n try {\n await recomputeVolcano(df, sp!, metric, colorDim,\n DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD, progress);\n // Re-rank labels against the (possibly new) metric, applying the\n // chosen count. Decoupled from selection — leaves the user's rows be.\n applyTopNLabels(df, sp!, labelTopNInput.value ?? getVolcanoTopN(df));\n } catch (e: any) {\n grok.shell.error(`Volcano update failed: ${e?.message ?? e}`);\n } finally {\n pi.close();\n if (willFetchLocation && sp) hideVolcanoBusy(sp);\n }\n })\n .show();\n }\n\n @grok.decorators.func()\n static async showHeatmap(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Heatmap')) return;\n if (!requireDifferentialExpression(df,\n 'Run Differential Expression first (Proteomics | Analyze | Differential Expression)')) return;\n\n // M4 — top-N is now user-configurable (was hardcoded 50). Small dialog so the\n // analyst can widen/narrow the heatmap; the ellipsis menu item implies it.\n const topNInput = ui.input.int('Top N proteins', {value: 50, min: 1});\n topNInput.setTooltip('How many of the most significant proteins (by adj. p-value) to show.');\n ui.dialog('Heatmap Options')\n .add(topNInput)\n .onOK(async () => {\n const topN = topNInput.value ?? 50;\n const pi = DG.TaskBarProgressIndicator.create('Creating heatmap...');\n try {\n const grid = await createExpressionHeatmap(df,\n {topN, title: `Heatmap: Top ${topN} DE Proteins`});\n tv.addViewer(grid);\n } finally {\n pi.close();\n }\n })\n .show();\n }\n\n @grok.decorators.func()\n static async showPcaPlot(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'PCA')) return;\n // PCA does NOT require DE -- it works after import/normalization\n const groups = getGroups(df);\n if (!groups) {\n grok.shell.warning('Annotate experimental groups first (Proteomics | Annotate Experiment)');\n return;\n }\n const allCols = [...groups.group1.columns, ...groups.group2.columns];\n const {viewer: sp, pcaDf} = createPcaPlot(df, allCols, groups, 'PCA: All Groups');\n pcaDf.name = `PCA: ${df.name}`;\n // PCA creates its own sample-level DataFrame -- open in separate table view\n const pcaTv = grok.shell.addTableView(pcaDf);\n pcaTv.addViewer(sp);\n }\n\n @grok.decorators.func()\n static async showGroupMeanCorrelation(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireDifferentialExpression(df,\n 'Run Differential Expression first (Proteomics | Analyze | Differential Expression)')) return;\n const groups = getGroups(df);\n if (!groups) {\n grok.shell.warning('Annotate experimental groups first (Proteomics | Annotate Experiment)');\n return;\n }\n const sp = createGroupMeanCorrelation(df);\n tv.addViewer(sp);\n }\n\n @grok.decorators.func()\n static async showQcDashboard(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'QC Dashboard')) return;\n openQcDashboard(df);\n }\n\n @grok.decorators.func()\n static async showSpcDashboard(): Promise<void> {\n await openSpcDashboard();\n }\n\n @grok.decorators.func()\n static async showAllVisualizations(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!tv || !df) { grok.shell.warning('No table open'); return; }\n if (!requireSampleLevelData(df, 'Show All Visualizations')) return;\n if (!requireDifferentialExpression(df, 'Run Differential Expression first')) return;\n // Volcano -- docked in current table view (protein-level)\n const groups = getGroups(df);\n const volcano = createVolcanoPlot(df);\n tv.addViewer(volcano);\n // Heatmap -- docked in current table view (protein-level)\n const heatmapPi = DG.TaskBarProgressIndicator.create('Creating heatmap...');\n try {\n const heatmap = await createExpressionHeatmap(df, {title: 'Heatmap: Top 50 DE Proteins'});\n tv.addViewer(heatmap);\n } finally {\n heatmapPi.close();\n }\n // PCA (if groups available) -- opens in SEPARATE table view (sample-level, different row count)\n if (groups) {\n const allCols = [...groups.group1.columns, ...groups.group2.columns];\n const {viewer: pcaViewer, pcaDf} = createPcaPlot(df, allCols, groups, 'PCA: All Groups');\n pcaDf.name = `PCA: ${df.name}`;\n const pcaTv = grok.shell.addTableView(pcaDf);\n pcaTv.addViewer(pcaViewer);\n }\n }\n\n @grok.decorators.func()\n static async enrichmentAnalysis(): Promise<void> {\n const df = grok.shell.tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n showEnrichmentDialog(df);\n }\n\n @grok.decorators.func()\n static async exportEnrichmentInputs(): Promise<void> {\n const df = grok.shell.tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n if (!requireDifferentialExpression(df,\n 'Run Differential Expression first (Proteomics | Analyze | Differential Expression)')) return;\n showEnrichmentInputExportDialog(df);\n }\n\n @grok.decorators.func()\n static async enrichmentCharts(): Promise<void> {\n const tv = grok.shell.tv;\n const df = tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n if (df.getTag('proteomics.enrichment') !== 'true') {\n grok.shell.warning('Run Enrichment Analysis first (Proteomics | Enrichment Analysis)');\n return;\n }\n // Find protein DataFrame(s) by proteomics.de_complete tag. If multiple are open,\n // pick the first but warn — the user may have meant a different one.\n const candidates = grok.shell.tables.filter((t: DG.DataFrame) => t.getTag('proteomics.de_complete') === 'true');\n if (candidates.length === 0) {\n grok.shell.warning('No protein table with DE results found. Enrichment charts will open without volcano linking.');\n openEnrichmentVisualization(df, df);\n return;\n }\n if (candidates.length > 1)\n grok.shell.warning(`Multiple protein tables with DE results found; linking enrichment to \"${candidates[0].name}\"`);\n openEnrichmentVisualization(df, candidates[0]);\n }\n\n @grok.decorators.func({\n name: 'Proteomics Demo',\n description: 'End-to-end proteomics differential-expression analysis on the HYE benchmark: ' +\n 'import → impute → differential expression → volcano + heatmap, with a QC dashboard tab ' +\n 'and the top hit pre-selected for its UniProt panel',\n meta: {demoPath: 'Proteomics | Differential Expression', isDemoDashboard: 'true'},\n })\n static async proteomicsDemo(): Promise<void> {\n await runProteomicsDemo();\n }\n\n @grok.decorators.func({\n name: 'Proteomics Enrichment Demo',\n description: 'Pathway enrichment (g:Profiler GO / KEGG / Reactome / WikiPathways) on a human ' +\n 'differential-expression result — cell-cycle up, oxidative-phosphorylation down — with the ' +\n 'enrichment charts cross-linked to the volcano',\n meta: {demoPath: 'Proteomics | Enrichment Analysis', isDemoDashboard: 'true'},\n })\n static async proteomicsEnrichmentDemo(): Promise<void> {\n await runEnrichmentDemo();\n }\n\n @grok.decorators.panel({\n name: 'Proteomics | UniProt',\n description: 'UniProt protein details',\n meta: {role: 'widgets'},\n })\n static uniprotPanelWidget(\n @grok.decorators.param({options: {semType: 'Proteomics-ProteinId'}}) proteinId: string,\n ): DG.Widget {\n return uniprotPanel(proteinId);\n }\n\n @grok.decorators.func()\n static async shareAnalysisForReview(): Promise<void> {\n const tv = grok.shell.tv;\n let df = tv?.dataFrame;\n if (!df) { grok.shell.warning('No table open'); return; }\n\n // Share may be invoked from the Enrichment Results tab, whose df is the\n // enrichment frame (no de_complete) rather than the analyzed protein table.\n // Resolve the protein DataFrame: use the current df if it's DE-complete,\n // otherwise find an analyzed table among open tables (mirrors the\n // enrichment-charts handler) so the user doesn't have to switch tabs first.\n if (df.getTag('proteomics.de_complete') !== 'true') {\n const candidates = grok.shell.tables.filter(\n (t: DG.DataFrame) => t.getTag('proteomics.de_complete') === 'true');\n if (candidates.length === 0) {\n requireDifferentialExpression(df,\n 'Run Differential Expression first (Proteomics | Analyze | Differential Expression)');\n return;\n }\n if (candidates.length > 1)\n grok.shell.warning(`Multiple analyzed tables open; sharing \"${candidates[0].name}\".`);\n df = candidates[0];\n }\n await showShareForReviewDialog(df);\n }\n\n @grok.decorators.panel({\n name: 'Proteomics | Shared Analysis',\n description: 'Audit context for a shared analysis snapshot',\n meta: {role: 'widgets'},\n })\n static publishedAnalysisPanelWidget(\n @grok.decorators.param({options: {semType: 'Proteomics-ProteinId'}}) proteinId: string,\n ): DG.Widget {\n return publishedAnalysisPanel(proteinId);\n }\n\n @grok.decorators.func({tags: ['autostart'], meta: {autostartImmediate: 'true'}})\n static async recoverPublishedProjectsOnStartup(): Promise<void> {\n const tryEvent: any =\n (grok.events as any).onProjectOpened ??\n (grok.events as any).onCurrentProjectChanged ??\n null;\n const handleOpen = async (): Promise<void> => {\n await new Promise((r) => setTimeout(r, 200));\n const tables = (grok.shell as any).tables as DG.DataFrame[] | undefined;\n if (!Array.isArray(tables)) return;\n for (const df of tables) {\n if (isPublished(df)) {\n try { await recoverPublishedProject(df); } catch (e: any) {\n grok.shell.warning(`Could not auto-recover shared analysis on open: ${e?.message ?? e}`);\n }\n }\n }\n };\n if (tryEvent && typeof tryEvent.subscribe === 'function') {\n tryEvent.subscribe(() => { void handleOpen(); });\n } else {\n const onViewAdded: any = (grok.events as any).onViewAdded;\n if (onViewAdded && typeof onViewAdded.subscribe === 'function') {\n onViewAdded.subscribe((view: DG.View) => {\n if ((view as any) instanceof DG.TableView) {\n const df = (view as any).dataFrame;\n if (df && isPublished(df)) {\n recoverPublishedProject(df).catch((e: any) => {\n grok.shell.warning(`Could not auto-recover shared analysis on open: ${e?.message ?? e}`);\n });\n }\n }\n });\n }\n }\n }\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {_package} from '../package';\nimport {parseSpectronautText} from '../parsers/spectronaut-parser';\nimport {getGroups} from '../analysis/experiment-setup';\nimport {imputeKnn} from '../analysis/imputation';\nimport {runDifferentialExpression} from '../analysis/differential-expression';\nimport {createVolcanoPlot} from '../viewers/volcano';\nimport {createExpressionHeatmap} from '../viewers/heatmap';\nimport {openQcDashboard} from '../viewers/qc-dashboard';\nimport {focusProtein} from '../panels/protein-focus';\n\n/**\n * The package's single \"richest endpoint\" demo. It takes the HYE benchmark (a\n * Spectronaut DIA report where Human, Yeast, and E. coli proteomes are mixed at\n * known, different ratios between two conditions — HYE mix A vs B, four\n * replicates each) all the way through the analysis pipeline and lands on the\n * fully-analyzed protein table with the Volcano and Expression Heatmap docked,\n * a QC dashboard on a second tab, and the most significant protein pre-selected\n * so its UniProt entry is already showing in the context panel.\n *\n * HYE is chosen deliberately: two whole species shift abundance between the\n * conditions, so hundreds of proteins are genuinely differential and the\n * volcano shows a strong, self-evident signal — the point of a \"richest\n * endpoint\" demo. (A spike-in benchmark like CPTAC is real but deliberately\n * subtle: at n=3 a plain t-test can't clear FDR, leaving an all-grey volcano.)\n *\n * Enrichment is intentionally NOT part of this demo: g:Profiler enrichment\n * assumes a single organism, and HYE is a three-species mix, so GO/pathway\n * enrichment would only map the human subset and mislead. Enrichment belongs in\n * a single-organism demo.\n *\n * The Spectronaut parser auto-annotates the two conditions from R.Condition and\n * tags the data preNormalized, so the demo skips straight to imputation + DE and\n * does NOT re-normalize — re-normalizing an already-normalized export would\n * distort the known species-ratio signal. Differential expression runs the\n * client-side Welch t-test, so the demo needs no R environment. The only network\n * touches are best-effort and cached: the parser's Ensembl gene-label lookup and\n * the UniProt context panel, both of which degrade gracefully offline. The\n * dataset ships at `files/demo/spectronaut-hye-demo.tsv` (see\n * `files/demo/README.md`).\n */\nexport async function runProteomicsDemo(): Promise<void> {\n const pi = DG.TaskBarProgressIndicator.create('Loading proteomics demo…');\n try {\n pi.update(5, 'Importing HYE benchmark (Spectronaut DIA)…');\n const text = await _package.files.readAsText('demo/spectronaut-hye-demo.tsv');\n const df = await parseSpectronautText(text);\n df.name = 'HYE benchmark';\n const analysisTv = grok.shell.addTableView(df);\n\n // Groups (HYE mix A / B) are auto-populated by the parser from R.Condition.\n const groups = getGroups(df);\n if (!groups) {\n grok.shell.warning('Demo: expected two auto-annotated conditions — ' +\n 'opened the table without running differential expression.');\n return;\n }\n const allCols = [...groups.group1.columns, ...groups.group2.columns];\n\n pi.update(40, 'Imputing missing values (KNN)…');\n imputeKnn(df, allCols);\n df.setTag('proteomics.imputed', 'true');\n\n pi.update(60, 'Differential expression (t-test)…');\n runDifferentialExpression(df, groups.group1.columns, groups.group2.columns,\n groups.group1.name, groups.group2.name);\n df.setTag('proteomics.de_method', 't-test');\n\n pi.update(78, 'Building volcano and heatmap…');\n const volcano = createVolcanoPlot(df);\n analysisTv.dockManager.dock(volcano, DG.DOCK_TYPE.RIGHT, null, 'Volcano', 0.5);\n\n const heatmap = await createExpressionHeatmap(df, {title: 'Heatmap: Top 50 DE Proteins'});\n analysisTv.dockManager.dock(heatmap, DG.DOCK_TYPE.DOWN, null, 'Heatmap', 0.45);\n\n // QC dashboard on a SECOND tab. openQcDashboard docks into grok.shell.tv, so\n // open a second table view over the same DataFrame (it becomes current), build\n // QC there, then land back on the analysis endpoint. Sharing one DataFrame\n // across two views is fine — QC adds its own columns; the volcano keeps its own.\n pi.update(90, 'Building QC dashboard tab…');\n const qcTv = grok.shell.addTableView(df);\n qcTv.name = 'HYE benchmark — QC';\n openQcDashboard(df);\n grok.shell.v = analysisTv;\n\n // Pre-select the most significant protein so the UniProt context panel is\n // already showing — a real accession from a spiked species, not the flat\n // human background. Shared with the import handlers (which focus row 0).\n focusProtein(df, topHitRow(df));\n\n pi.update(100, 'Done');\n grok.shell.info('Proteomics demo: HYE benchmark analyzed end to end ' +\n '(import → impute → differential expression). Yeast and E. coli proteins ' +\n 'shift abundance between the two conditions, so the volcano separates the ' +\n 'genuinely differential proteins from the constant human background. ' +\n 'QC charts are on the second tab; the top hit is selected for its UniProt panel.');\n } finally {\n pi.close();\n }\n}\n\n/**\n * Row index of the most significant protein (smallest adj.p among the\n * significant rows) to pre-select for the UniProt panel. Falls back to row 0\n * when there is no significant protein or no adj.p column.\n */\nfunction topHitRow(df: DG.DataFrame): number {\n const adj = df.col('adj.p-value');\n const sig = df.col('significant');\n if (!adj) return 0;\n\n let best = -1;\n let bestP = Infinity;\n for (let i = 0; i < df.rowCount; i++) {\n if (sig && !sig.get(i)) continue;\n if (adj.isNone(i)) continue;\n const p = adj.get(i) as number;\n if (p < bestP) { bestP = p; best = i; }\n }\n return best < 0 ? 0 : best;\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {_package} from '../package';\nimport {setGroups} from '../analysis/experiment-setup';\nimport {runEnrichmentPipeline} from '../analysis/enrichment';\nimport {openEnrichmentVisualization} from '../viewers/enrichment-viewers';\nimport {createVolcanoPlot} from '../viewers/volcano';\nimport {focusProtein} from '../panels/protein-focus';\nimport {SEMTYPE, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\n\n/**\n * Single-organism pathway-enrichment demo. Loads a small engineered HUMAN\n * differential-expression result (Treatment vs Control) whose regulated proteins\n * form two coherent, textbook-enriched sets — cell-cycle / mitosis UP and\n * oxidative phosphorylation DOWN — over a diverse non-significant background, so\n * g:Profiler returns crisp, recognizable terms. It opens the volcano, runs\n * enrichment (GO / KEGG / Reactome / WikiPathways), and docks the enrichment\n * charts cross-linked to the volcano: selecting a term highlights its proteins.\n *\n * This is the counterpart to the main `Proteomics Demo`, which uses the\n * three-species HYE benchmark — a mix that is deliberately unsuitable for\n * enrichment (g:Profiler assumes a single organism). The dataset ships at\n * `files/demo/enrichment-demo.csv` (see `files/demo/README.md`).\n *\n * Enrichment calls g:Profiler over the network; if the service is unreachable\n * the demo still opens the DE table + volcano and explains how to retry.\n */\nexport async function runEnrichmentDemo(): Promise<void> {\n const pi = DG.TaskBarProgressIndicator.create('Loading enrichment demo…');\n try {\n pi.update(10, 'Loading human DE result…');\n const text = await _package.files.readAsText('demo/enrichment-demo.csv');\n const df = DG.DataFrame.fromCsv(text);\n // Kept free of \"Enrichment\" so the derived enrichment view reads cleanly as\n // \"<source> — Enrichment\" (mirrors the QC demo's \"<source> — QC\" naming).\n df.name = 'Treatment vs Control (human)';\n\n // Semantic-type the columns so the pipeline and panels find them by type,\n // not by name — mirrors what the parsers do on a real import.\n const setSem = (name: string, sem: string): void => {\n const c = df.col(name);\n if (c) c.semType = sem;\n };\n setSem('Protein ID', SEMTYPE.PROTEIN_ID);\n setSem('Gene', SEMTYPE.GENE_SYMBOL);\n setSem('log2FC', SEMTYPE.LOG2FC);\n setSem('p-value', SEMTYPE.P_VALUE);\n setSem('adj.p-value', SEMTYPE.P_VALUE);\n\n // A pre-computed DE result (like a Spectronaut Candidates import): mark DE\n // complete and record group NAMES so the volcano legend reads naturally.\n // There are no per-sample columns, so the group column lists stay empty.\n df.setTag('proteomics.source', 'generic');\n df.setTag('proteomics.de_method', 'precomputed');\n df.setTag('proteomics.de_complete', 'true');\n setGroups(df, {group1: {name: 'Treatment', columns: []}, group2: {name: 'Control', columns: []}});\n\n const tv = grok.shell.addTableView(df);\n const volcano = createVolcanoPlot(df);\n tv.dockManager.dock(volcano, DG.DOCK_TYPE.RIGHT, null, 'Volcano', 0.5);\n\n // Headline protein (row 0 = a cell-cycle hit) selected for its UniProt panel.\n focusProtein(df, 0);\n\n pi.update(45, 'Running g:Profiler enrichment (GO / KEGG / Reactome)…');\n try {\n const {enrichmentDf, mapped, total} = await runEnrichmentPipeline(\n df, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD, 'hsapiens',\n ['GO:BP', 'GO:MF', 'GO:CC', 'KEGG', 'REAC', 'WP'], true);\n pi.update(90, 'Opening enrichment charts…');\n // openEnrichmentVisualization opens the enrichment view and makes it current.\n // Name it \"<source> — Enrichment\" (mirrors the DE demo's \"<source> — QC\" tab)\n // and land back on the main view, so the demo-app framework's leaf-rename puts\n // \"Enrichment Analysis\" on the main view — matching where the DE demo lands.\n const enrichTv = openEnrichmentVisualization(enrichmentDf, df);\n enrichTv.name = `${df.name} — Enrichment`;\n grok.shell.v = tv;\n grok.shell.info(\n `Enrichment demo: ${enrichmentDf.rowCount} over-represented terms across ${mapped}/${total} genes. ` +\n 'Up-regulated proteins are enriched for cell-cycle / mitosis; down-regulated for oxidative ' +\n 'phosphorylation. Select a term row to highlight its proteins on the volcano.');\n } catch (e: any) {\n grok.shell.warning(\n `Enrichment demo: g:Profiler enrichment could not run (${e?.message ?? e}). ` +\n 'The DE table and volcano are open — retry via Proteomics | Enrichment Analysis ' +\n 'once the service is reachable.');\n }\n\n pi.update(100, 'Done');\n } finally {\n pi.close();\n }\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {\n DE_COMPLETE_TAG, PublishOptions, findPriorShare, slugifyTarget,\n} from './publish-state';\nimport {publishAnalysis} from './publish-project';\nimport {reviewNamePrefix, verifyPublishedDashboard} from './publish-settings';\n\n/**\n * Analyst-facing share dialog. Single entry point into the publish flow —\n * every reviewer-touchable string flows through here (target label, group\n * label, note placeholder, republish banner, confirmation summary, error\n * messages, success state). The Pitfall 14 biologist-jargon audit is\n * enforced here.\n *\n * Async (`Promise<void>`) per W-6 — loads reviewer groups via\n * `dapi.groups.list()` before composing the dialog. Plan 07 menu handler\n * must `await` (or `void`-fire) it.\n *\n * - Republish-detection banner reactively driven by {@link findPriorShare}\n * - PUB-08 reactive confirmation summary (W-4): always-visible block that\n * updates on every input change so the analyst sees the exact resulting\n * Project name / team / supersede status BEFORE clicking OK\n * - Mailto link in the success state (PUB-13, P2) uses {@link buildMailtoUrl}\n * imported from `./publish-state` (NOT redefined here per B-1)\n */\nexport async function showShareForReviewDialog(df: DG.DataFrame): Promise<void> {\n if (df.getTag(DE_COMPLETE_TAG) !== 'true') {\n grok.shell.warning('Run Differential Expression first.');\n return;\n }\n\n const allGroups = await grok.dapi.groups.list();\n const allUsersId = (DG.Group as any).defaultGroupsIds?.['All users'];\n const filteredGroups = (allGroups ?? []).filter((g: any) => {\n if (g == null) return false;\n if (g.hidden) return false;\n if (g.personal) return false;\n if (allUsersId && g.id === allUsersId) return false;\n return true;\n });\n\n if (filteredGroups.length === 0) {\n grok.shell.warning('No teams available to share with. Ask an admin to create a reviewer team.');\n return;\n }\n\n const groupByName = new Map<string, DG.Group>();\n for (const g of filteredGroups) {\n const name = (g as any).friendlyName ?? (g as any).name ?? '';\n if (name && !groupByName.has(name)) groupByName.set(name, g);\n }\n const groupItems = Array.from(groupByName.keys());\n\n const targetInput = ui.input.string('Target', {value: ''});\n targetInput.setTooltip('Free text — your team\\'s name for this target (e.g., MYH7-DMD, muscle-atrophy panel)');\n\n const groupInput = ui.input.choice('Share with team', {\n value: groupItems[0],\n items: groupItems,\n nullable: false,\n });\n\n const noteInput = (ui.input as any).textArea\n ? (ui.input as any).textArea('Note for reviewers', {value: ''})\n : ui.input.string('Note for reviewers', {value: ''});\n\n // Per-share verification toggle. Defaults to the package setting\n // (`verifyPublishedDashboard`), but lets the user skip the heavy reopen-and-check\n // round trip for a fast demo share without changing the deployment default.\n const verifyInput = ui.input.bool('Verify published dashboard', {value: verifyPublishedDashboard()});\n verifyInput.setTooltip(\n 'Re-open the shared dashboard after publishing to confirm it survives a reload. ' +\n 'On = safer (recommended for client deliverables); off = faster share.');\n\n const banner = ui.div();\n banner.style.cssText = 'background:#fff3cd; padding:8px; border-radius:4px; margin-bottom:8px; display:none;';\n\n const summary = ui.div();\n summary.style.cssText = 'background:#f0f0f0; padding:8px; border-radius:4px; margin:8px 0; font-family: monospace; font-size:11px;';\n\n let priorVersion: DG.Project | null = null;\n\n const parsePriorVersionN = (priorName: string | null | undefined): number => {\n if (!priorName) return 0;\n const m = /-v(\\d+)-/.exec(priorName);\n if (!m) return 0;\n const n = parseInt(m[1], 10);\n return Number.isFinite(n) ? n : 0;\n };\n\n const updateBannerAndSummary = async (): Promise<void> => {\n const target = (targetInput.value ?? '').trim();\n const groupName = groupInput.value;\n const group = groupName ? groupByName.get(groupName) ?? null : null;\n const slug = target ? slugifyTarget(target) : '<no-target>';\n const dateStr = new Date().toISOString().slice(0, 10);\n\n if (target && group) {\n try { priorVersion = await findPriorShare(target, group); }\n catch { priorVersion = null; }\n } else {\n priorVersion = null;\n }\n\n const priorN = parsePriorVersionN(priorVersion ? (priorVersion as any).name : null);\n const nextVersion = priorN > 0 ? priorN + 1 : 1;\n\n if (priorVersion) {\n banner.textContent =\n `⚠ This will share as v${nextVersion} and supersede \"${(priorVersion as any).name}\". ` +\n `The previous version stays available for reference.`;\n banner.style.display = 'block';\n } else {\n banner.style.display = 'none';\n }\n\n const projectName = `${reviewNamePrefix()}-${slug}-v${nextVersion}-${dateStr}`;\n const groupLabel = group ? ((group as any).friendlyName ?? (group as any).name ?? '<unnamed team>') : '<pick a team>';\n const statusLabel = priorVersion\n ? `Will supersede \"${(priorVersion as any).name}\" (v${nextVersion})`\n : 'New share';\n\n summary.innerHTML = '';\n summary.appendChild(ui.divText(`Project: ${projectName}`));\n summary.appendChild(ui.divText(`Will be visible to: ${groupLabel}`));\n summary.appendChild(ui.divText(`Status: ${statusLabel}`));\n summary.appendChild(ui.divText(`Date: ${dateStr}`));\n };\n\n targetInput.onChanged.subscribe(() => { void updateBannerAndSummary(); });\n groupInput.onChanged.subscribe(() => { void updateBannerAndSummary(); });\n\n await updateBannerAndSummary();\n\n ui.dialog('Share Analysis for Review')\n .add(targetInput)\n .add(groupInput)\n .add(noteInput)\n .add(verifyInput)\n .add(banner)\n .add(summary)\n .onOK(async () => {\n const target = (targetInput.value ?? '').trim();\n if (!target) { grok.shell.warning('Target is required.'); return; }\n const group = groupInput.value ? groupByName.get(groupInput.value) : null;\n if (!group) { grok.shell.warning('Pick a team to share with.'); return; }\n\n const opts: PublishOptions = {\n target,\n reviewerGroup: group,\n note: (noteInput.value ?? '') as string,\n priorVersion,\n verify: verifyInput.value ?? true,\n };\n\n try {\n const project = await publishAnalysis(df, opts);\n const groupName = (group as any).friendlyName ?? (group as any).name ?? '(unnamed team)';\n // Single non-modal confirmation — the published project is browsable in the\n // Spaces tree, so no modal or action links are needed. publishAnalysis no\n // longer emits its own toast, so this is the one and only confirmation.\n grok.shell.info(`Shared as ${(project as any).name} with team ${groupName}.`);\n } catch (e: any) {\n grok.shell.error(`Share failed: ${e?.message ?? String(e)}`);\n }\n })\n .show();\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\nimport {fetchUniProtEntry} from '../analysis/subcellular-location';\nimport {getGroups, GroupAssignment} from '../analysis/experiment-setup';\nimport {findColumn} from '../utils/column-detection';\nimport {SEMTYPE, DIRECTION_COLORS_BASE} from '../utils/proteomics-types';\n\n\n/** UniProt REST API response types */\ninterface UniProtEntry {\n accession?: string;\n proteinDescription?: {\n recommendedName?: { fullName?: { value?: string } };\n submissionNames?: Array<{ fullName?: { value?: string } }>;\n };\n genes?: Array<{ geneName?: { value?: string } }>;\n organism?: { scientificName?: string; commonName?: string };\n comments?: Array<{\n commentType?: string;\n texts?: Array<{ value?: string }>;\n }>;\n uniProtKBCrossReferences?: Array<{\n database?: string;\n id?: string;\n properties?: Array<{ key?: string; value?: string }>;\n }>;\n}\n\ninterface GoTerms {\n mf: string[];\n bp: string[];\n cc: string[];\n}\n\n\n/**\n * Parse a UniProt accession from a raw protein ID value.\n * Handles:\n * - Bare accessions: \"P04637\"\n * - UniProt format prefixes: \"sp|P04637|P53_HUMAN\" or \"tr|Q67890|...\"\n * - Semicolon-delimited protein groups: \"P12345;Q67890\" (uses first)\n */\nexport function parseAccession(raw: string): string | null {\n if (!raw || !raw.trim())\n return null;\n\n // Take first entry if semicolon-delimited\n const first = raw.split(';')[0].trim();\n if (!first)\n return null;\n\n // Handle sp|ACC|NAME or tr|ACC|NAME format\n const pipeMatch = first.match(/^(?:sp|tr)\\|([A-Za-z0-9_-]+)\\|/);\n if (pipeMatch)\n return pipeMatch[1];\n\n // Handle CPTAC/UPS format: P00167ups|CYB5_HUMAN_UPS — extract accession before \"ups\" suffix\n const upsMatch = first.match(/^([A-Za-z0-9]+?)ups\\|/i);\n if (upsMatch)\n return upsMatch[1];\n\n // Handle generic ACC|NAME format (single pipe, no sp/tr prefix)\n if (first.includes('|'))\n return first.split('|')[0].trim();\n\n // Bare accession -- strip trailing \"ups\" suffix (CPTAC spike-in format) then return\n const bareMatch = first.match(/^([A-Za-z0-9_-]+)$/);\n if (bareMatch) {\n const acc = bareMatch[1];\n return acc.replace(/ups$/i, '');\n }\n\n return null;\n}\n\n\n/** Fetch protein data from UniProt. Delegates to the shared subcellular-location\n * module's cached fetcher so re-clicking a protein doesn't re-hit the network\n * (closes the folded cache-uniprot todo); the shared fetcher keeps the same\n * fetchProxy / warn+null discipline this panel relied on. */\nasync function fetchUniProtData(accession: string): Promise<UniProtEntry | null> {\n return (await fetchUniProtEntry(accession)) as UniProtEntry | null;\n}\n\n\n/** Extract and group GO terms by aspect (F/P/C). */\nfunction extractGoTerms(entry: UniProtEntry): GoTerms {\n const mf: string[] = [];\n const bp: string[] = [];\n const cc: string[] = [];\n\n for (const xref of entry.uniProtKBCrossReferences ?? []) {\n if (xref.database !== 'GO') continue;\n const term = xref.properties?.find((p) => p.key === 'GoTerm')?.value ?? '';\n if (term.startsWith('F:')) mf.push(term.substring(2));\n else if (term.startsWith('P:')) bp.push(term.substring(2));\n else if (term.startsWith('C:')) cc.push(term.substring(2));\n }\n return {mf, bp, cc};\n}\n\n\n/** Get protein name, falling back to submission name if no recommended name. */\nfunction getProteinName(entry: UniProtEntry): string {\n return entry.proteinDescription?.recommendedName?.fullName?.value ??\n entry.proteinDescription?.submissionNames?.[0]?.fullName?.value ??\n 'Unknown';\n}\n\n\n/**\n * R3 / D-11 — locate the host DataFrame for a clicked protein in the UniProt panel.\n * Walks grok.shell.tables for tables whose `getGroups()` is set AND whose primary\n * protein-id column resolves the queried accession in some row. Prefers the\n * table behind the current table view when multiple match.\n */\nexport function findHostDataFrameForProtein(accession: string): DG.DataFrame | null {\n if (!accession) return null;\n const candidates: DG.DataFrame[] = [];\n for (const df of grok.shell.tables) {\n if (!getGroups(df)) continue;\n const idCol = findColumn(df, SEMTYPE.PROTEIN_ID,\n ['primary protein id', 'protein id', 'uniprot', 'accession']);\n if (!idCol) continue;\n for (let i = 0; i < df.rowCount; i++) {\n const raw = idCol.get(i) as string | null;\n if (raw && parseAccession(raw) === accession) {\n candidates.push(df);\n break;\n }\n }\n }\n if (candidates.length === 0) return null;\n const activeDf = grok.shell.tv?.dataFrame ?? null;\n if (activeDf && candidates.includes(activeDf)) return activeDf;\n return candidates[0];\n}\n\n/**\n * R3 / D-11 — compact SVG bar chart (one bar per experimental group, mean ± SD\n * whiskers, magenta/cyan per D-04). Returns null when the protein has no row\n * in the host DataFrame; the caller renders the empty-state message instead.\n * Returns the empty-state element when the row exists but every group has zero\n * non-null observations.\n *\n * Source: 14-RESEARCH.md §\"Pattern 6 — Inline SVG bar chart in a panel\".\n */\nexport function renderPerGroupBars(df: DG.DataFrame, accession: string): HTMLElement | null {\n const groups = getGroups(df);\n if (!groups) return null;\n\n const idCol = findColumn(df, SEMTYPE.PROTEIN_ID,\n ['primary protein id', 'protein id', 'uniprot', 'accession']);\n if (!idCol) return null;\n\n let rowIdx = -1;\n for (let i = 0; i < df.rowCount; i++) {\n const raw = idCol.get(i) as string | null;\n if (raw && parseAccession(raw) === accession) { rowIdx = i; break; }\n }\n if (rowIdx < 0) return null;\n\n const stats = [groups.group1, groups.group2].map((g) => {\n const vals = g.columns\n .map((n) => df.col(n))\n .filter((c): c is DG.Column => c != null)\n .map((c) => (c.isNone(rowIdx) ? NaN : c.get(rowIdx) as number))\n .filter((v) => typeof v === 'number' && !isNaN(v) && v !== DG.FLOAT_NULL);\n const n = vals.length;\n if (n === 0) return {name: g.name, mean: NaN, sd: NaN, n: 0};\n const mean = vals.reduce((s, v) => s + v, 0) / n;\n const variance = n > 1 ? vals.reduce((s, v) => s + (v - mean) ** 2, 0) / (n - 1) : 0;\n return {name: g.name, mean, sd: Math.sqrt(variance), n};\n });\n if (stats.every((s) => s.n === 0))\n return ui.divText('No per-group quantities available for this protein');\n\n // SVG layout — locked spacing per 14-UI-SPEC §\"Spacing Scale > Per-group bar-chart\".\n const W = 200, H = 120, BAR_W = 24, GAP = 8, PAD = 24;\n const maxVal = Math.max(\n ...stats.map((s) => (isNaN(s.mean) ? 0 : s.mean + (isNaN(s.sd) ? 0 : s.sd))),\n );\n const safeMax = maxVal > 0 ? maxVal : 1;\n const scale = (v: number) => H - PAD - (v / safeMax) * (H - 2 * PAD);\n // D-04 LOCKED palette: group1=magenta, group2=cyan — derived from the shared\n // DIRECTION_COLORS_BASE (ARGB) so the panel can't drift from the volcano.\n // #RRGGBB (uppercase) matches the SVG fill the panel has always emitted.\n const hexRgb = (argb: number) => '#' + (argb & 0xFFFFFF).toString(16).padStart(6, '0').toUpperCase();\n const COLORS = [\n hexRgb(DIRECTION_COLORS_BASE.enrichedG1),\n hexRgb(DIRECTION_COLORS_BASE.enrichedG2),\n ];\n const svgNs = 'http://www.w3.org/2000/svg';\n const svg = document.createElementNS(svgNs, 'svg');\n svg.setAttribute('width', String(W));\n svg.setAttribute('height', String(H));\n\n stats.forEach((s, i) => {\n const x = PAD + i * (BAR_W + GAP * 2);\n if (s.n === 0) return;\n const y = scale(s.mean);\n const rect = document.createElementNS(svgNs, 'rect');\n rect.setAttribute('x', String(x));\n rect.setAttribute('y', String(y));\n rect.setAttribute('width', String(BAR_W));\n rect.setAttribute('height', String(Math.max(0, H - PAD - y)));\n rect.setAttribute('fill', COLORS[i] ?? hexRgb(DIRECTION_COLORS_BASE.notSig));\n svg.appendChild(rect);\n\n // Mean±SD whiskers only when SD is defined (n > 1).\n if (s.n > 1 && !isNaN(s.sd)) {\n const whiskerX = x + BAR_W / 2;\n const yTop = scale(s.mean + s.sd);\n const yBot = scale(s.mean - s.sd);\n const line = document.createElementNS(svgNs, 'line');\n line.setAttribute('x1', String(whiskerX));\n line.setAttribute('x2', String(whiskerX));\n line.setAttribute('y1', String(yTop));\n line.setAttribute('y2', String(yBot));\n line.setAttribute('stroke', '#333');\n line.setAttribute('stroke-width', '1');\n svg.appendChild(line);\n }\n\n const label = document.createElementNS(svgNs, 'text');\n label.setAttribute('x', String(x + BAR_W / 2));\n label.setAttribute('y', String(H - 4));\n label.setAttribute('text-anchor', 'middle');\n label.setAttribute('font-size', '10');\n label.textContent = `${s.name} (n=${s.n})`;\n svg.appendChild(label);\n });\n\n const container = ui.divV([svg]);\n stats.forEach((s) => {\n if (s.n > 0) {\n const txt = ui.divText(`${s.name}: mean=${s.mean.toFixed(2)} SD=${s.sd.toFixed(2)}`);\n txt.style.fontSize = '0.85em';\n container.appendChild(txt);\n }\n });\n return container;\n}\n\n\n/** Build the widget DOM for a successfully fetched UniProt entry. */\nexport function renderUniProtWidget(entry: UniProtEntry, accession: string): HTMLElement {\n const container = document.createElement('div');\n\n // Prominent link to full UniProt entry\n const link = ui.link(\n `UniProt: ${accession}`,\n `https://www.uniprot.org/uniprot/${accession}`,\n 'Open full UniProt entry',\n );\n link.style.fontWeight = 'bold';\n link.style.display = 'block';\n link.style.marginBottom = '8px';\n container.appendChild(link);\n\n // Summary table\n const proteinName = getProteinName(entry);\n const gene = entry.genes?.[0]?.geneName?.value ?? 'Unknown';\n const organism = entry.organism?.scientificName ?? 'Unknown';\n\n const funcComment = entry.comments?.find((c) => c.commentType === 'FUNCTION');\n let funcText = funcComment?.texts?.[0]?.value ?? '';\n if (funcText.length > 200)\n funcText = funcText.substring(0, 200) + '...';\n\n const map: Record<string, string> = {\n 'Protein': proteinName,\n 'Gene': gene,\n 'Organism': organism,\n };\n if (funcText)\n map['Function'] = funcText;\n\n container.appendChild(ui.tableFromMap(map));\n\n // GO terms grouped by category\n const go = extractGoTerms(entry);\n const goCategories: Array<{label: string; terms: string[]}> = [\n {label: 'Molecular Function', terms: go.mf},\n {label: 'Biological Process', terms: go.bp},\n {label: 'Cellular Component', terms: go.cc},\n ];\n\n const hasGoTerms = goCategories.some((c) => c.terms.length > 0);\n if (hasGoTerms) {\n const goHeader = ui.divText('GO Terms');\n goHeader.style.fontWeight = 'bold';\n goHeader.style.marginTop = '8px';\n goHeader.style.marginBottom = '4px';\n container.appendChild(goHeader);\n\n for (const cat of goCategories) {\n if (cat.terms.length === 0) continue;\n const label = ui.divText(cat.label);\n label.style.fontWeight = 'bold';\n label.style.fontSize = '0.9em';\n label.style.marginTop = '4px';\n container.appendChild(label);\n\n const termText = cat.terms.slice(0, 5).join(', ');\n const termDiv = ui.divText(termText);\n termDiv.style.fontSize = '0.85em';\n termDiv.style.marginLeft = '8px';\n container.appendChild(termDiv);\n }\n }\n\n // R3 / D-11 — per-group quantities bar chart (Phase 14)\n // The panel's `accession` parameter is the canonical source; threading it\n // through findHostDataFrameForProtein avoids depending on whichever optional\n // field the UniProtData shape happens to expose.\n const hostDf = findHostDataFrameForProtein(accession);\n if (hostDf) {\n const perGroupHeader = ui.divText('Per-Group Quantities');\n perGroupHeader.style.fontWeight = 'bold';\n perGroupHeader.style.marginTop = '8px';\n perGroupHeader.style.marginBottom = '4px';\n container.appendChild(perGroupHeader);\n const bars = renderPerGroupBars(hostDf, accession);\n container.appendChild(bars ?? ui.divText('No per-group quantities available for this protein'));\n }\n\n return container;\n}\n\n\n/**\n * Main panel function. Accepts a raw protein ID string, returns a DG.Widget\n * with async loading (spinner while fetching).\n */\nexport function uniprotPanel(proteinId: string): DG.Widget {\n const accession = parseAccession(proteinId);\n\n if (!accession)\n return new DG.Widget(ui.divText('No valid UniProt accession found'));\n\n return new DG.Widget(ui.wait(async () => {\n const data = await fetchUniProtData(accession);\n if (!data)\n return ui.divText(`Unable to fetch UniProt data for ${accession}`);\n return renderUniProtWidget(data, accession);\n }));\n}\n","import * as DG from 'datagrok-api/dg';\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {log2TransformColumns, addPrimaryColumnIfNeeded} from './shared-utils';\nimport {resolveGeneLabels} from '../utils/gene-label-resolver';\n\n/** Per-sample intensity column suffixes in FragPipe's combined_protein.tsv,\n * in order of quantitative preference. MaxLFQ is the FragPipe-recommended\n * LFQ quant; bare \" Intensity\" is the summed peptide intensity. Razor is\n * the razor-protein attribution and not normally used as the primary quant. */\nconst INTENSITY_SUFFIXES = [' MaxLFQ Intensity', ' Intensity', ' Razor Intensity'] as const;\n\n/** Column name variants for protein-level identifiers in FragPipe output.\n * `Protein ID` is the UniProt accession; `Protein` is the full FASTA header\n * (e.g., `sp|P12345|GENE_HUMAN`) which we prefer only if `Protein ID` is missing. */\nconst PROTEIN_ID_COLUMNS = ['Protein ID', 'Protein'];\n\n/** Column name variants for gene symbols. */\nconst GENE_NAME_COLUMNS = ['Gene', 'Gene Names', 'Gene Symbol'];\n\n/** Decoy / contaminant prefixes to filter out at the row level.\n * `contam_` is FragPipe/Philosopher's convention; `rev_` is Philosopher's decoy\n * prefix (usually filtered upstream, but defensive); CON__/REV__ cover the\n * case where the FASTA was MaxQuant-formatted. */\nconst CONTAMINANT_PREFIXES = ['contam_', 'rev_', 'CON__', 'REV__'];\n\n/** Finds the first existing column from a list of name candidates. */\nfunction findCol(df: DG.DataFrame, names: readonly string[]): DG.Column | null {\n for (const name of names) {\n const col = df.col(name);\n if (col)\n return col;\n }\n return null;\n}\n\n/** Checks whether a header is a per-sample intensity column.\n * Returns the matched suffix (lowercased) or null. */\nfunction matchIntensitySuffix(header: string): string | null {\n const lower = header.toLowerCase();\n for (const suffix of INTENSITY_SUFFIXES) {\n if (lower.endsWith(suffix.toLowerCase()) && lower.length > suffix.length)\n return suffix.toLowerCase();\n }\n return null;\n}\n\n/** Marks rows for exclusion when their primary protein identifier starts with\n * any contaminant/decoy prefix. Checks both `Protein ID` and `Protein` because\n * Philosopher contam_/rev_ prefixes appear on whichever column is populated. */\nfunction filterContaminantRows(df: DG.DataFrame): void {\n const candidates = ['Protein ID', 'Protein'];\n const cols: DG.Column[] = [];\n for (const name of candidates) {\n const c = df.col(name);\n if (c) cols.push(c);\n }\n if (cols.length === 0) return;\n\n for (let i = 0; i < df.rowCount; i++) {\n for (const col of cols) {\n const val = col.get(i);\n if (typeof val !== 'string') continue;\n let matched = false;\n for (const prefix of CONTAMINANT_PREFIXES) {\n if (val.startsWith(prefix)) {\n matched = true;\n break;\n }\n }\n if (matched) {\n df.filter.set(i, false, false);\n break;\n }\n }\n }\n}\n\n/** Scans the header row to find intensity columns and forces them to `double`\n * during CSV import. Without this, fromCsv can mistype large-integer intensities\n * (or all-zero / all-blank samples) as boolean or int. Mirrors the same guard\n * used by the MaxQuant parser. */\nfunction buildIntensityColumnOptions(text: string): DG.CsvImportColumnOptions[] {\n const newlineIdx = text.indexOf('\\n');\n const firstLine = (newlineIdx >= 0 ? text.substring(0, newlineIdx) : text).replace(/\\r$/, '');\n const headers = firstLine.split('\\t');\n const opts: DG.CsvImportColumnOptions[] = [];\n for (const header of headers) {\n if (matchIntensitySuffix(header))\n opts.push({name: header, type: 'double'});\n }\n return opts;\n}\n\n/** Returns the set of intensity columns to log2-transform. If MaxLFQ Intensity\n * columns exist, prefer them and drop the redundant bare \" Intensity\" / \" Razor\n * Intensity\" columns for the same sample. If MaxLFQ is absent (e.g. spectral-\n * count-only run, or LFQ not enabled), fall back to \" Intensity\". Razor is only\n * used as a last resort. Returned columns still get SEMTYPE.INTENSITY below. */\nfunction pickQuantColumns(df: DG.DataFrame): string[] {\n type Bucket = {maxLfq?: string; intensity?: string; razor?: string};\n const samples = new Map<string, Bucket>();\n\n for (const name of df.columns.names()) {\n const col = df.col(name);\n if (!col) continue;\n if (col.type !== DG.COLUMN_TYPE.FLOAT && col.type !== DG.COLUMN_TYPE.INT &&\n col.type !== DG.COLUMN_TYPE.BIG_INT)\n continue;\n const lower = name.toLowerCase();\n let sample: string | null = null;\n let kind: keyof Bucket | null = null;\n if (lower.endsWith(' maxlfq intensity')) {\n sample = name.substring(0, name.length - ' MaxLFQ Intensity'.length);\n kind = 'maxLfq';\n } else if (lower.endsWith(' razor intensity')) {\n sample = name.substring(0, name.length - ' Razor Intensity'.length);\n kind = 'razor';\n } else if (lower.endsWith(' intensity')) {\n sample = name.substring(0, name.length - ' Intensity'.length);\n kind = 'intensity';\n }\n if (!sample || !kind) continue;\n if (!samples.has(sample)) samples.set(sample, {});\n samples.get(sample)![kind] = name;\n }\n\n const chosen: string[] = [];\n for (const bucket of samples.values()) {\n if (bucket.maxLfq) chosen.push(bucket.maxLfq);\n else if (bucket.intensity) chosen.push(bucket.intensity);\n else if (bucket.razor) chosen.push(bucket.razor);\n }\n return chosen;\n}\n\n/** Assigns semantic types to ID, gene, and the chosen per-sample intensity columns.\n * Only `chosenQuant` columns receive SEMTYPE.INTENSITY — the redundant Razor /\n * bare-Intensity columns we dropped from log2 transform must not surface as\n * intensities in downstream pickers. */\nfunction assignSemanticTypes(df: DG.DataFrame, chosenQuant: string[]): void {\n const proteinCol = findCol(df, PROTEIN_ID_COLUMNS);\n if (proteinCol)\n proteinCol.semType = SEMTYPE.PROTEIN_ID;\n\n const geneCol = findCol(df, GENE_NAME_COLUMNS);\n if (geneCol)\n geneCol.semType = SEMTYPE.GENE_SYMBOL;\n\n for (const name of chosenQuant) {\n const col = df.col(name);\n if (col) col.semType = SEMTYPE.INTENSITY;\n }\n}\n\n/** Finds the source column for primary extraction from FragPipe-specific name\n * variants and delegates to shared addPrimaryColumnIfNeeded. */\nfunction addPrimaryColumnFromVariants(df: DG.DataFrame, sourceNames: readonly string[],\n newName: string, semType: string): void {\n const srcCol = findCol(df, sourceNames);\n if (!srcCol) return;\n addPrimaryColumnIfNeeded(df, srcCol.name, newName, semType);\n}\n\n/** Parses a FragPipe `combined_protein.tsv` into a filtered, typed DataFrame.\n *\n * Applies:\n * - Contaminant/decoy row filtering (`contam_`, `rev_`, plus MaxQuant-style\n * CON__/REV__ as a fallback)\n * - Semantic type assignment (PROTEIN_ID, GENE_SYMBOL, INTENSITY)\n * - Primary protein/gene split for semicolon-delimited identifier lists\n * - Log2 transform of the preferred quantitative intensity columns\n * (MaxLFQ Intensity > Intensity > Razor Intensity, picked per sample)\n *\n * The returned DataFrame is ready for the standard pipeline: Annotate\n * Experiment -> Normalize -> Impute -> Differential Expression -> Viewers. */\nexport async function parseFragPipeText(text: string): Promise<DG.DataFrame> {\n const columnImportOptions = buildIntensityColumnOptions(text);\n const raw = DG.DataFrame.fromCsv(text, {delimiter: '\\t', columnImportOptions});\n\n raw.filter.init((_i) => true);\n filterContaminantRows(raw);\n raw.filter.fireChanged();\n\n const df = raw.clone(raw.filter);\n\n // Choose one quant column per sample for log2 transform.\n const chosen = pickQuantColumns(df);\n assignSemanticTypes(df, chosen);\n\n addPrimaryColumnFromVariants(df, PROTEIN_ID_COLUMNS, 'Primary Protein ID', SEMTYPE.PROTEIN_ID);\n addPrimaryColumnFromVariants(df, GENE_NAME_COLUMNS, 'Primary Gene Name', SEMTYPE.GENE_SYMBOL);\n\n log2TransformColumns(df, chosen);\n\n df.setTag('proteomics.source', 'fragpipe');\n\n await resolveGeneLabels(df);\n\n return df;\n}\n","import * as DG from 'datagrok-api/dg';\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {log2TransformColumns, addPrimaryColumnIfNeeded} from './shared-utils';\nimport {resolveGeneLabels} from '../utils/gene-label-resolver';\n\n/** Intensity column prefixes to detect, checked in this order.\n * \"intensity\" must be last since it is a substring of \"lfq intensity\". */\nconst INTENSITY_PREFIXES = ['lfq intensity', 'ibaq', 'reporter intensity', 'intensity'];\n\n/** Column name variants for filter columns across MaxQuant versions. */\nconst FILTER_COLUMNS = {\n contaminant: ['Potential contaminant', 'Potential.contaminant'],\n reverse: ['Reverse'],\n onlyBySite: ['Only identified by site', 'Only.identified.by.site'],\n} as const;\n\n/** Column name variants for protein IDs. */\nconst PROTEIN_ID_COLUMNS = ['Protein IDs', 'Majority protein IDs'];\n\n/** Column name variants for gene names. */\nconst GENE_NAME_COLUMNS = ['Gene names', 'Gene name'];\n\n/** Finds the first existing column from a list of name candidates. */\nfunction findCol(df: DG.DataFrame, names: readonly string[]): DG.Column | null {\n for (const name of names) {\n const col = df.col(name);\n if (col)\n return col;\n }\n return null;\n}\n\n/** Marks rows for exclusion where the given column has value \"+\". */\nfunction filterByMarker(df: DG.DataFrame, colNames: readonly string[]): void {\n const col = findCol(df, colNames);\n if (!col) return;\n for (let i = 0; i < df.rowCount; i++) {\n if (col.get(i) === '+')\n df.filter.set(i, false, false);\n }\n}\n\n/** Marks rows for exclusion when any protein-id column starts with CON__/REV__.\n * Scans every column in PROTEIN_ID_COLUMNS rather than the first match — MaxQuant\n * sometimes drops the prefix from `Protein IDs` but retains it in `Majority protein IDs`. */\nfunction filterByIdPrefix(df: DG.DataFrame): void {\n const cols: DG.Column[] = [];\n for (const name of PROTEIN_ID_COLUMNS) {\n const c = df.col(name);\n if (c) cols.push(c);\n }\n if (cols.length === 0) return;\n for (let i = 0; i < df.rowCount; i++) {\n for (const col of cols) {\n const val = col.get(i);\n if (typeof val === 'string' && (val.startsWith('CON__') || val.startsWith('REV__'))) {\n df.filter.set(i, false, false);\n break;\n }\n }\n }\n}\n\n/** Finds the source column for primary extraction from MaxQuant-specific name variants,\n * then delegates to shared addPrimaryColumnIfNeeded which handles semicolon detection. */\nfunction addPrimaryColumnFromVariants(df: DG.DataFrame, sourceNames: readonly string[],\n newName: string, semType: string): void {\n const srcCol = findCol(df, sourceNames);\n if (!srcCol) return;\n addPrimaryColumnIfNeeded(df, srcCol.name, newName, semType);\n}\n\n/** Scans header row to find intensity column names and build columnImportOptions\n * that force them to double. Prevents fromCsv from mistyping large-integer\n * intensity columns as boolean. */\nfunction buildIntensityColumnOptions(text: string): DG.CsvImportColumnOptions[] {\n const newlineIdx = text.indexOf('\\n');\n const firstLine = (newlineIdx >= 0 ? text.substring(0, newlineIdx) : text).replace(/\\r$/, '');\n const headers = firstLine.split('\\t');\n const opts: DG.CsvImportColumnOptions[] = [];\n for (const header of headers) {\n const lower = header.toLowerCase();\n for (const prefix of INTENSITY_PREFIXES) {\n if (lower.startsWith(prefix)) {\n opts.push({name: header, type: 'double'});\n break;\n }\n }\n }\n return opts;\n}\n\n/** Detects intensity columns by MaxQuant-specific prefix matching and\n * delegates to shared log2TransformColumns for the actual transformation. */\nfunction processIntensityColumns(df: DG.DataFrame): void {\n const intensityNames: string[] = [];\n for (const name of df.columns.names()) {\n const col = df.col(name);\n if (!col) continue;\n if (col.type !== DG.COLUMN_TYPE.FLOAT && col.type !== DG.COLUMN_TYPE.INT)\n continue;\n const lowerName = name.toLowerCase();\n for (const prefix of INTENSITY_PREFIXES) {\n if (lowerName.startsWith(prefix)) {\n intensityNames.push(name);\n break;\n }\n }\n }\n log2TransformColumns(df, intensityNames);\n}\n\n/** Assigns semantic types to protein ID and gene name columns. */\nfunction assignSemanticTypes(df: DG.DataFrame): void {\n const proteinCol = findCol(df, PROTEIN_ID_COLUMNS);\n if (proteinCol)\n proteinCol.semType = SEMTYPE.PROTEIN_ID;\n\n const geneCol = findCol(df, GENE_NAME_COLUMNS);\n if (geneCol)\n geneCol.semType = SEMTYPE.GENE_SYMBOL;\n}\n\n/** Parses MaxQuant proteinGroups.txt TSV text into a filtered, typed DataFrame.\n *\n * Applies standard proteomics filtering:\n * - Removes contaminant rows ('+' marker or CON__ prefix)\n * - Removes reverse hits ('+' marker or REV__ prefix)\n * - Removes only-identified-by-site rows\n *\n * Adds log2-transformed intensity columns and semantic type annotations. */\nexport async function parseMaxQuantText(text: string): Promise<DG.DataFrame> {\n const columnImportOptions = buildIntensityColumnOptions(text);\n const raw = DG.DataFrame.fromCsv(text, {delimiter: '\\t', columnImportOptions});\n\n // Apply row filters\n raw.filter.init((_i) => true);\n filterByMarker(raw, FILTER_COLUMNS.contaminant);\n filterByMarker(raw, FILTER_COLUMNS.reverse);\n filterByMarker(raw, FILTER_COLUMNS.onlyBySite);\n filterByIdPrefix(raw);\n raw.filter.fireChanged();\n\n // Clone filtered rows\n const df = raw.clone(raw.filter);\n\n // Assign semantic types to ID and gene columns\n assignSemanticTypes(df);\n\n // Parse semicolon-delimited fields into primary columns (only if semicolons present)\n addPrimaryColumnFromVariants(df, PROTEIN_ID_COLUMNS, 'Primary Protein ID', SEMTYPE.PROTEIN_ID);\n addPrimaryColumnFromVariants(df, GENE_NAME_COLUMNS, 'Primary Gene Name', SEMTYPE.GENE_SYMBOL);\n\n // Detect and log2-transform intensity columns\n processIntensityColumns(df);\n\n df.setTag('proteomics.source', 'maxquant');\n\n await resolveGeneLabels(df);\n\n return df;\n}\n","import * as DG from 'datagrok-api/dg';\nimport {SEMTYPE} from '../utils/proteomics-types';\n\n/** Creates log2-transformed copies of the specified columns.\n * Original columns get SEMTYPE.INTENSITY. New log2 columns get SEMTYPE.INTENSITY\n * and names prefixed with 'log2(...)'.\n * Zero, negative, and null values produce DG.FLOAT_NULL in the log2 column. */\nexport function log2TransformColumns(df: DG.DataFrame, colNames: string[]): void {\n let nonFiniteCount = 0;\n for (const name of colNames) {\n const col = df.col(name);\n if (!col) continue;\n col.semType = SEMTYPE.INTENSITY;\n const log2Name = `log2(${name})`;\n const log2Col = df.columns.addNewFloat(log2Name);\n log2Col.init((i) => {\n if (col.isNone(i)) return DG.FLOAT_NULL;\n const val = Number(col.get(i));\n if (isNaN(val)) { nonFiniteCount++; return DG.FLOAT_NULL; }\n return val > 0 ? Math.log2(val) : DG.FLOAT_NULL;\n });\n log2Col.semType = SEMTYPE.INTENSITY;\n }\n if (nonFiniteCount > 0)\n console.warn(`log2TransformColumns: ${nonFiniteCount} non-numeric value(s) dropped to null`);\n}\n\n/** Copies intensity columns with log2() prefix for already-transformed data.\n * No math transformation -- just copies values into log2-named columns\n * for downstream compatibility. Sets both original and log2 column\n * semType = SEMTYPE.INTENSITY. */\nexport function copyAsLog2Columns(df: DG.DataFrame, colNames: string[]): void {\n for (const name of colNames) {\n const col = df.col(name);\n if (!col) continue;\n col.semType = SEMTYPE.INTENSITY;\n const log2Name = `log2(${name})`;\n const log2Col = df.columns.addNewFloat(log2Name);\n log2Col.init((i) => col.isNone(i) ? DG.FLOAT_NULL : Number(col.get(i)));\n log2Col.semType = SEMTYPE.INTENSITY;\n }\n}\n\n/** Creates a primary (first semicolon-delimited entry) column if semicolons\n * are detected in source data. Skips creation entirely if no semicolons found. */\nexport function addPrimaryColumnIfNeeded(\n df: DG.DataFrame, sourceColName: string, newName: string, semType: string,\n): void {\n const srcCol = df.col(sourceColName);\n if (!srcCol) return;\n\n // Scan for semicolons -- skip creation if none found\n let hasSemicolon = false;\n for (let i = 0; i < df.rowCount && !hasSemicolon; i++) {\n const val = srcCol.get(i);\n if (typeof val === 'string' && val.includes(';'))\n hasSemicolon = true;\n }\n if (!hasSemicolon) return;\n\n const newCol = df.columns.addNewString(newName);\n newCol.init((i) => {\n const val = srcCol.get(i);\n if (typeof val !== 'string' || val.length === 0) return null;\n const idx = val.indexOf(';');\n return idx >= 0 ? val.substring(0, idx) : val;\n });\n newCol.semType = semType;\n}\n\n/** Detects whether intensity columns appear to be log2-transformed.\n * Samples up to 200 non-null numeric values across the specified columns.\n * Heuristic: values >= 1000 suggest raw intensities; values in [0, 30] suggest log2. */\nexport function detectLog2Status(\n df: DG.DataFrame, colNames: string[],\n): {isLog2: boolean; message: string} {\n let inLog2Range = 0;\n let inRawRange = 0;\n let total = 0;\n const maxSamples = 200;\n\n // Only count values that fall in either bucket — ambiguous \"middle\" values\n // (e.g. 31..999) carry no signal about scale, and counting them in `total`\n // makes the ratios at L101-105 unreliable on heterogeneous datasets.\n for (const name of colNames) {\n const col = df.col(name);\n if (!col) continue;\n if (col.type !== DG.COLUMN_TYPE.FLOAT && col.type !== DG.COLUMN_TYPE.INT && col.type !== DG.COLUMN_TYPE.BIG_INT) continue;\n for (let i = 0; i < df.rowCount && total < maxSamples; i++) {\n if (col.isNone(i)) continue;\n const val = Number(col.get(i));\n if (val >= 0 && val <= 30) { inLog2Range++; total++; }\n else if (val >= 1000) { inRawRange++; total++; }\n }\n if (total >= maxSamples) break;\n }\n\n if (total === 0)\n return {isLog2: false, message: 'No intensity values found'};\n if (inRawRange / total > 0.5)\n return {isLog2: false, message: 'Data appears to be raw intensities'};\n if (inLog2Range / total > 0.8)\n return {isLog2: true, message: 'Data appears to be already log2-transformed'};\n return {isLog2: false, message: 'Could not determine data scale'};\n}\n\n/** Detects delimiter by checking the first line for tab vs comma prevalence.\n * Returns '\\t' or ','. */\nexport function detectDelimiter(text: string): string {\n const newlineIdx = text.indexOf('\\n');\n const firstLine = newlineIdx >= 0 ? text.substring(0, newlineIdx) : text;\n const tabs = (firstLine.match(/\\t/g) || []).length;\n const commas = (firstLine.match(/,/g) || []).length;\n return tabs > commas ? '\\t' : ',';\n}\n\n/** Scans string columns for names containing protein-related keywords.\n * Returns the first matching column, or null. */\nexport function autoSuggestProteinIdColumn(df: DG.DataFrame): DG.Column | null {\n const keywords = ['protein', 'accession', 'uniprot'];\n for (const col of df.columns.toList()) {\n if (col.type !== DG.COLUMN_TYPE.STRING) continue;\n const lower = col.name.toLowerCase();\n for (const kw of keywords) {\n if (lower.includes(kw))\n return col;\n }\n }\n return null;\n}\n\n/** Scans string columns for names containing gene-related keywords.\n * Returns the first matching column, or null. */\nexport function autoSuggestGeneNameColumn(df: DG.DataFrame): DG.Column | null {\n const keywords = ['gene', 'symbol', 'gene_name', 'genename'];\n for (const col of df.columns.toList()) {\n if (col.type !== DG.COLUMN_TYPE.STRING) continue;\n const lower = col.name.toLowerCase();\n for (const kw of keywords) {\n if (lower.includes(kw))\n return col;\n }\n }\n return null;\n}\n\n/** Scans numeric column names for intensity-related keywords.\n * Returns all matching column names. */\nexport function autoSuggestIntensityColumns(df: DG.DataFrame): string[] {\n const keywords = ['intensity', 'lfq', 'ibaq', 'tmt', 'reporter', 'abundance'];\n const result: string[] = [];\n for (const col of df.columns.toList()) {\n if (col.type !== DG.COLUMN_TYPE.FLOAT && col.type !== DG.COLUMN_TYPE.INT && col.type !== DG.COLUMN_TYPE.BIG_INT) continue;\n const lower = col.name.toLowerCase();\n for (const kw of keywords) {\n if (lower.includes(kw)) {\n result.push(col.name);\n break;\n }\n }\n }\n return result;\n}\n","import * as DG from 'datagrok-api/dg';\nimport {SEMTYPE, DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\nimport {addPrimaryColumnIfNeeded, detectDelimiter} from './shared-utils';\nimport {resolveGeneLabels} from '../utils/gene-label-resolver';\nimport {setGroups} from '../analysis/experiment-setup';\n\n/** Column name variants for protein-level identifiers in Spectronaut Candidates output.\n * Modern Spectronaut prefixes with `PG.`; older / re-exported reports may strip it. */\nconst PROTEIN_ID_COLUMNS = ['PG.ProteinGroups', 'ProteinGroups', 'Protein Groups'];\n\n/** Column name variants for gene symbols. */\nconst GENE_NAME_COLUMNS = ['PG.Genes', 'Genes', 'Gene Names'];\n\n/** Column name variants for log2 fold change. Spectronaut's canonical name is\n * `AVG Log2 Ratio`; some export profiles abbreviate or rename it. */\nconst LOG2FC_COLUMNS = ['AVG Log2 Ratio', 'Log2 Ratio', 'AVG Log2 Fold Change'];\n\n/** Column name variants for the FDR-adjusted significance metric. Spectronaut emits\n * `Qvalue` from its built-in Storey FDR; some export profiles use `Q-Value` or\n * `AdjustedPValue`. */\nconst ADJ_P_COLUMNS = ['Qvalue', 'Q-Value', 'Q.Value', 'AdjustedPValue', 'Adjusted P-Value'];\n\n/** Column name variants for the raw p-value (optional in Candidates reports). */\nconst P_VALUE_COLUMNS = ['Pvalue', 'PValue', 'P-Value', 'P.Value'];\n\n/** The declared contrast string, kept verbatim. Form: \"group1 / group2\".\n * Exported so callers (e.g. the multi-contrast filter in package.ts) locate the\n * column by the same name candidates instead of re-inlining the literals. */\nexport const COMPARISON_COLUMNS = ['Comparison (group1/group2)', 'Comparison'];\n\n/** Per-group mean abundance, swapped when a row's sign is flipped (A6: only\n * when BOTH are present). */\nconst AVG_GROUP_QTY_NUM_COLUMNS = ['AVG Group Quantity Numerator'];\nconst AVG_GROUP_QTY_DEN_COLUMNS = ['AVG Group Quantity Denominator'];\n\n/** Declared numerator/denominator condition labels, relabeled on flip. */\nconst CONDITION_NUM_COLUMNS = ['Condition Numerator'];\nconst CONDITION_DEN_COLUMNS = ['Condition Denominator'];\n\n/** Decoy / contaminant prefixes to filter at the row level. Mirrors the FragPipe\n * parser — Spectronaut libraries may include MaxQuant-style CON__/REV__ entries\n * when the FASTA was re-used across pipelines. */\nconst CONTAMINANT_PREFIXES = ['contam_', 'rev_', 'CON__', 'REV__'];\n\n// Default significance thresholds (DEFAULT_FC_THRESHOLD / DEFAULT_P_THRESHOLD)\n// are imported from proteomics-types — used when the input does not pre-compute\n// a boolean `significant` column, matching runDifferentialExpression.\n\n/** Finds the first existing column from a list of name candidates. */\nfunction findCol(df: DG.DataFrame, names: readonly string[]): DG.Column | null {\n for (const name of names) {\n const col = df.col(name);\n if (col)\n return col;\n }\n return null;\n}\n\n/** Marks rows for exclusion when the protein-group identifier starts with any\n * contaminant/decoy prefix. */\nfunction filterContaminantRows(df: DG.DataFrame, idColName: string): void {\n const col = df.col(idColName);\n if (!col) return;\n for (let i = 0; i < df.rowCount; i++) {\n const val = col.get(i);\n if (typeof val !== 'string') continue;\n for (const prefix of CONTAMINANT_PREFIXES) {\n if (val.startsWith(prefix)) {\n df.filter.set(i, false, false);\n break;\n }\n }\n }\n}\n\n/** Renames a column to the canonical downstream name. Skips the rename if the\n * canonical name is already taken by a different column — defensive against\n * malformed inputs that already contain both `Qvalue` and `adj.p-value`. */\nfunction renameToCanonical(df: DG.DataFrame, src: DG.Column, canonical: string): void {\n if (src.name === canonical) return;\n const existing = df.col(canonical);\n if (existing && existing !== src) return;\n src.name = canonical;\n}\n\n/**\n * Normalizes each row's sign so positive log2FC = enriched in the canonical\n * group1. Ported from CK-omics `create_subset_data` (CKomics_tool2.py:1625-1662)\n * and locked by 13-WAVE0-FINDINGS.md A2: the canonical orientation is the first\n * parseable declared \"g1 / g2\"; ONLY rows whose declared comparison is the exact\n * reverse (\"g2 / g1\") are flipped — never unconditional. A flip negates log2FC,\n * swaps AVG Group Quantity Numerator/Denominator (only if BOTH present — A6),\n * and relabels Comparison + Condition Numerator/Denominator to canonical.\n * Pure (no shell/UI side effects). Single-orientation / unparseable input is\n * left byte-identical (Pitfall 4 — never invert on ambiguity).\n */\nfunction normalizeCandidatesSign(df: DG.DataFrame): void {\n const cmpCol = findCol(df, COMPARISON_COLUMNS);\n if (!cmpCol) return;\n const n = df.rowCount;\n\n // Canonical orientation = first parseable \"g1 / g2\".\n let canonical: string | null = null;\n let canonG1 = '';\n let canonG2 = '';\n for (let i = 0; i < n; i++) {\n const v = cmpCol.get(i);\n if (typeof v === 'string' && v.includes(' / ')) {\n const parts = v.split(' / ');\n if (parts.length === 2 && parts[0] && parts[1]) {\n canonical = v;\n canonG1 = parts[0];\n canonG2 = parts[1];\n break;\n }\n }\n }\n if (canonical === null) return; // no parseable comparison → all canonical\n const reversed = `${canonG2} / ${canonG1}`;\n\n // Flip ONLY rows whose declared comparison is the exact reverse of canonical.\n const flip = new Uint8Array(n);\n let anyFlip = false;\n for (let i = 0; i < n; i++) {\n if (cmpCol.get(i) === reversed) {\n flip[i] = 1;\n anyFlip = true;\n }\n }\n if (!anyFlip) return; // single-orientation / no reversed rows → unchanged\n\n // log2FC sign flip. Bulk getRawData → number[] → init (memory\n // feedback_dg_column_bulk_init). FLOAT_NULL is preserved by writing the\n // sentinel number back, never returning JS null (memory\n // feedback_dg_column_init_null_sentinel). number[] (not Float32Array) keeps\n // full double precision for large AVG Group Quantity values.\n const fcCol = df.col('log2FC')!;\n const fcRaw = fcCol.getRawData() as Float32Array | Float64Array;\n const newFc: number[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const v = fcRaw[i];\n newFc[i] = (v === DG.FLOAT_NULL) ? DG.FLOAT_NULL : (flip[i] ? -v : v);\n }\n fcCol.init((i) => newFc[i]);\n\n // AVG Group Quantity swap — only when BOTH columns exist (A6 guard).\n const numCol = findCol(df, AVG_GROUP_QTY_NUM_COLUMNS);\n const denCol = findCol(df, AVG_GROUP_QTY_DEN_COLUMNS);\n if (numCol && denCol) {\n const numRaw = numCol.getRawData() as Float32Array | Float64Array;\n const denRaw = denCol.getRawData() as Float32Array | Float64Array;\n const newNum: number[] = new Array(n);\n const newDen: number[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const nv = numRaw[i];\n const dv = denRaw[i];\n newNum[i] = flip[i] ? dv : nv;\n newDen[i] = flip[i] ? nv : dv;\n }\n numCol.init((i) => newNum[i]);\n denCol.init((i) => newDen[i]);\n }\n\n // Relabel Comparison + Condition for flipped rows (string init, not per-row\n // set — memory feedback_dg_column_bulk_init).\n const cmpVals: string[] = new Array(n);\n for (let i = 0; i < n; i++)\n cmpVals[i] = flip[i] ? canonical! : (cmpCol.get(i) as string);\n cmpCol.init((i) => cmpVals[i]);\n\n const condNumCol = findCol(df, CONDITION_NUM_COLUMNS);\n const condDenCol = findCol(df, CONDITION_DEN_COLUMNS);\n if (condNumCol && condDenCol) {\n const cnVals: string[] = new Array(n);\n const cdVals: string[] = new Array(n);\n for (let i = 0; i < n; i++) {\n cnVals[i] = flip[i] ? canonG1 : (condNumCol.get(i) as string);\n cdVals[i] = flip[i] ? canonG2 : (condDenCol.get(i) as string);\n }\n condNumCol.init((i) => cnVals[i]);\n condDenCol.init((i) => cdVals[i]);\n }\n}\n\n/** Parses a Spectronaut Candidates report into a DataFrame shaped like the output\n * of `runDifferentialExpression` — pre-computed `log2FC`, `p-value` (optional),\n * `adj.p-value`, and `significant` columns. Sets `proteomics.de_complete` so the\n * downstream volcano/heatmap/enrichment viewers light up without running DE.\n *\n * Required input columns (any spelling):\n * - Protein group: `PG.ProteinGroups` / `ProteinGroups`\n * - log2FC: `AVG Log2 Ratio` / `Log2 Ratio` / `AVG Log2 Fold Change`\n * - Adj. p-value: `Qvalue` / `Q-Value` / `AdjustedPValue` (Spectronaut's\n * Storey-FDR output is the canonical Qvalue)\n *\n * Optional:\n * - Gene symbol: `PG.Genes` / `Genes` / `Gene Names`\n * - Raw p-value: `Pvalue` / `PValue` / `P-Value`\n * - `Comparison` / `Comparison (group1/group2)` — kept as-is for reference.\n *\n * Notes:\n * - Multi-comparison files (one row per protein × per comparison) are accepted\n * verbatim; users filter the resulting DataFrame by the `Comparison` column.\n * - Significance is computed from |log2FC| ≥ 1.0 and adj.p-value ≤ 0.05 by\n * default, matching `runDifferentialExpression`'s defaults. */\nexport async function parseSpectronautCandidatesText(text: string): Promise<DG.DataFrame> {\n const delimiter = detectDelimiter(text);\n const raw = DG.DataFrame.fromCsv(text, {delimiter});\n\n const idCol = findCol(raw, PROTEIN_ID_COLUMNS);\n if (!idCol)\n throw new Error(`Spectronaut Candidates: missing protein-group column ` +\n `(expected one of ${PROTEIN_ID_COLUMNS.join(', ')})`);\n\n if (!findCol(raw, LOG2FC_COLUMNS))\n throw new Error(`Spectronaut Candidates: missing log2 ratio column ` +\n `(expected one of ${LOG2FC_COLUMNS.join(', ')})`);\n\n if (!findCol(raw, ADJ_P_COLUMNS))\n throw new Error(`Spectronaut Candidates: missing q-value column ` +\n `(expected one of ${ADJ_P_COLUMNS.join(', ')})`);\n\n raw.filter.init((_i) => true);\n filterContaminantRows(raw, idCol.name);\n raw.filter.fireChanged();\n\n const df = raw.clone(raw.filter);\n\n // Re-resolve columns on the cloned frame (clone preserves names but not refs)\n const idCol2 = findCol(df, PROTEIN_ID_COLUMNS)!;\n const log2fcCol = findCol(df, LOG2FC_COLUMNS)!;\n const adjPCol = findCol(df, ADJ_P_COLUMNS)!;\n const geneCol = findCol(df, GENE_NAME_COLUMNS);\n const pValCol = findCol(df, P_VALUE_COLUMNS);\n\n renameToCanonical(df, log2fcCol, 'log2FC');\n renameToCanonical(df, adjPCol, 'adj.p-value');\n if (pValCol)\n renameToCanonical(df, pValCol, 'p-value');\n\n idCol2.semType = SEMTYPE.PROTEIN_ID;\n if (geneCol) geneCol.semType = SEMTYPE.GENE_SYMBOL;\n df.col('log2FC')!.semType = SEMTYPE.LOG2FC;\n df.col('adj.p-value')!.semType = SEMTYPE.P_VALUE;\n if (df.col('p-value'))\n df.col('p-value')!.semType = SEMTYPE.P_VALUE;\n\n addPrimaryColumnIfNeeded(df, idCol2.name, 'Primary Protein ID', SEMTYPE.PROTEIN_ID);\n if (geneCol)\n addPrimaryColumnIfNeeded(df, geneCol.name, 'Primary Gene Name', SEMTYPE.GENE_SYMBOL);\n\n // R3/D-08: per-row sign normalization BEFORE significance (|log2FC| is\n // unchanged by a sign flip, so significance is orientation-invariant).\n normalizeCandidatesSign(df);\n\n const sigCol = df.columns.addNewBool('significant');\n const fcRaw = df.col('log2FC')!.getRawData() as Float32Array | Float64Array;\n const adjPRaw = df.col('adj.p-value')!.getRawData() as Float32Array | Float64Array;\n sigCol.init((i) => {\n const fc = fcRaw[i];\n const adjP = adjPRaw[i];\n if (fc === DG.FLOAT_NULL || adjP === DG.FLOAT_NULL) return false;\n return Math.abs(fc) >= DEFAULT_FC_THRESHOLD && adjP <= DEFAULT_P_THRESHOLD;\n });\n\n df.setTag('proteomics.source', 'spectronaut-candidates');\n df.setTag('proteomics.de_complete', 'true');\n df.setTag('proteomics.de_method', 'spectronaut');\n\n // Name the contrast groups (e.g. DMT / WT) from the report's Condition\n // Numerator / Denominator (or the \"num / den\" Comparison string) so the\n // volcano legend + title show real names instead of generic group1/group2.\n // Candidates carries no per-sample intensities, so the column lists stay\n // empty — downstream Annotate/Normalize/Impute/DE are skipped via\n // de_complete, and the volcano reads only the names. group1 = Numerator\n // (positive log2FC, magenta), group2 = Denominator (cyan).\n let g1Name = firstNonEmpty(findCol(df, CONDITION_NUM_COLUMNS));\n let g2Name = firstNonEmpty(findCol(df, CONDITION_DEN_COLUMNS));\n if (!g1Name || !g2Name) {\n const cmp = firstNonEmpty(findCol(df, COMPARISON_COLUMNS));\n if (cmp && cmp.includes('/')) {\n const [a, b] = cmp.split('/').map((s) => s.trim());\n g1Name = g1Name ?? (a || null);\n g2Name = g2Name ?? (b || null);\n }\n }\n if (g1Name && g2Name) {\n setGroups(df, {\n group1: {name: g1Name, columns: []},\n group2: {name: g2Name, columns: []},\n });\n }\n\n await resolveGeneLabels(df);\n\n return df;\n}\n\n/** First non-empty trimmed string value in a column, or null. */\nfunction firstNonEmpty(col: DG.Column | null): string | null {\n if (!col) return null;\n for (let i = 0; i < col.length; i++) {\n const v = col.get(i);\n if (v != null && String(v).trim().length > 0) return String(v).trim();\n }\n return null;\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {\n log2TransformColumns, copyAsLog2Columns, detectLog2Status,\n addPrimaryColumnIfNeeded,\n} from './shared-utils';\nimport {setGroups} from '../analysis/experiment-setup';\nimport {resolveGeneLabels} from '../utils/gene-label-resolver';\n\n/** Required Spectronaut columns for detection. */\nconst REQUIRED_COLUMNS = ['R.Condition', 'R.Replicate', 'PG.ProteinGroups'];\n\n/** Protein-group quantity column candidates, in preference order. `PG.IBAQ` is the\n * historical Spectronaut export; modern long-form reports use `PG.Quantity` (MaxLFQ\n * or top-N peptide sum). Both are constant per (protein-group, run). */\nconst QUANTITY_COLUMNS = ['PG.IBAQ', 'PG.Quantity'];\n\n/** Result of pivoting Spectronaut long-format data. */\ninterface PivotResult {\n proteinMap: Map<string, Map<string, number>>;\n sampleKeys: string[];\n sampleFileNames: Map<string, string>;\n organisms: Map<string, string>;\n /** Phase 16 SPC seed (D-01): earliest observed R.RunDate as ISO-8601, null if absent/unparseable. */\n earliestRunDate?: string | null;\n /** Phase 16 SPC seed (D-01): first non-empty R.InstrumentMethod cell, null if absent. */\n firstInstrumentMethod?: string | null;\n}\n\n/** Tries to parse a raw R.RunDate cell into a comparable epoch-ms; returns\n * null when the value is empty or `Date` cannot parse it. */\nfunction tryParseRunDate(raw: string): number | null {\n if (!raw || raw.trim().length === 0) return null;\n const t = Date.parse(raw);\n return Number.isNaN(t) ? null : t;\n}\n\n/** Pivots Spectronaut long-format rows into protein -> sample -> quantity map.\n * Filters CON__/REV__ proteins and rows exceeding q-value threshold.\n * Non-numeric q-values (e.g., 'Profiled', 'NaN') are treated as passing. */\nfunction pivotSpectronaut(\n longDf: DG.DataFrame,\n quantityColName: string,\n qValueThreshold: number,\n): PivotResult {\n const condCol = longDf.col('R.Condition')!;\n const replCol = longDf.col('R.Replicate')!;\n const protCol = longDf.col('PG.ProteinGroups')!;\n const ibaqCol = longDf.col(quantityColName)!;\n const qvalCol = longDf.col('EG.Qvalue');\n const fileCol = longDf.col('R.FileName');\n const orgCol = longDf.col('PG.Organisms');\n // Phase 16 SPC-seed columns (D-01): OPTIONAL; never added to REQUIRED_COLUMNS\n // so v1.3 inputs without them still parse.\n const runDateCol = longDf.col('R.RunDate');\n const instrMethodCol = longDf.col('R.InstrumentMethod');\n\n const proteinMap = new Map<string, Map<string, number>>();\n const sampleSet = new Set<string>();\n const sampleFileNames = new Map<string, string>();\n const organisms = new Map<string, string>();\n let earliestRunDateMs: number | null = null;\n let earliestRunDateIso: string | null = null;\n let firstInstrumentMethod: string | null = null;\n\n for (let i = 0; i < longDf.rowCount; i++) {\n // Q-value filter: numeric values > threshold are excluded; non-numeric pass\n if (qvalCol) {\n if (qvalCol.isNone(i)) {\n // null q-value: treat as passing\n } else {\n const raw = qvalCol.get(i);\n const qval = Number(raw);\n if (!isNaN(qval) && qval > qValueThreshold)\n continue;\n }\n }\n\n const protein = protCol.get(i) as string;\n if (!protein) continue;\n if (protein.startsWith('CON__') || protein.startsWith('REV__')) continue;\n\n const condition = String(condCol.get(i));\n const replicate = String(replCol.get(i));\n const sampleKey = `${condition}_${replicate}`;\n sampleSet.add(sampleKey);\n\n if (!proteinMap.has(protein))\n proteinMap.set(protein, new Map<string, number>());\n\n // First-encountered value wins (PG.IBAQ is constant per protein+sample)\n if (!proteinMap.get(protein)!.has(sampleKey) && !ibaqCol.isNone(i))\n proteinMap.get(protein)!.set(sampleKey, Number(ibaqCol.get(i)));\n\n if (fileCol && !sampleFileNames.has(sampleKey) && !fileCol.isNone(i))\n sampleFileNames.set(sampleKey, fileCol.get(i) as string);\n if (orgCol && !organisms.has(protein) && !orgCol.isNone(i))\n organisms.set(protein, orgCol.get(i) as string);\n\n // SPC seed: single-pass accumulators (Plan 16-04 Perf Decision Option A).\n if (runDateCol && !runDateCol.isNone(i)) {\n const raw = String(runDateCol.get(i));\n const ms = tryParseRunDate(raw);\n if (ms !== null && (earliestRunDateMs === null || ms < earliestRunDateMs)) {\n earliestRunDateMs = ms;\n earliestRunDateIso = new Date(ms).toISOString();\n }\n }\n if (instrMethodCol && firstInstrumentMethod === null && !instrMethodCol.isNone(i)) {\n const raw = String(instrMethodCol.get(i));\n if (raw.trim().length > 0) firstInstrumentMethod = raw;\n }\n }\n\n return {\n proteinMap,\n sampleKeys: Array.from(sampleSet).sort(),\n sampleFileNames,\n organisms,\n earliestRunDate: earliestRunDateIso,\n firstInstrumentMethod,\n };\n}\n\n/** Builds wide protein-by-sample DataFrame from pivot result. */\nfunction buildWideDataFrame(result: PivotResult): DG.DataFrame {\n const proteins = Array.from(result.proteinMap.keys());\n const n = proteins.length;\n\n const proteinCol = DG.Column.fromStrings('PG.ProteinGroups', proteins);\n proteinCol.semType = SEMTYPE.PROTEIN_ID;\n\n const cols: DG.Column[] = [proteinCol];\n\n // Add organisms column if any were collected\n if (result.organisms.size > 0) {\n const orgValues = proteins.map((p) => result.organisms.get(p) ?? '');\n const orgCol = DG.Column.fromStrings('PG.Organisms', orgValues);\n cols.push(orgCol);\n }\n\n for (const sampleKey of result.sampleKeys) {\n const values = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n const sampleMap = result.proteinMap.get(proteins[i])!;\n values[i] = sampleMap.has(sampleKey) ? sampleMap.get(sampleKey)! : DG.FLOAT_NULL;\n }\n const col = DG.Column.fromFloat32Array(sampleKey, values);\n col.semType = SEMTYPE.INTENSITY;\n if (result.sampleFileNames.has(sampleKey))\n col.setTag('spectronaut.fileName', result.sampleFileNames.get(sampleKey)!);\n cols.push(col);\n }\n\n return DG.DataFrame.fromColumns(cols);\n}\n\n/** Auto-populates experimental groups from R.Condition when exactly 2 conditions exist.\n * Groups use log2-prefixed column names for downstream analysis compatibility. */\nfunction autoPopulateGroups(df: DG.DataFrame, sampleKeys: string[]): void {\n const conditionMap = new Map<string, string[]>();\n for (const key of sampleKeys) {\n const lastUnderscore = key.lastIndexOf('_');\n const condition = key.substring(0, lastUnderscore);\n if (!conditionMap.has(condition))\n conditionMap.set(condition, []);\n conditionMap.get(condition)!.push(`log2(${key})`);\n }\n\n const conditions = Array.from(conditionMap.keys());\n if (conditions.length === 2) {\n setGroups(df, {\n group1: {name: conditions[0], columns: conditionMap.get(conditions[0])!},\n group2: {name: conditions[1], columns: conditionMap.get(conditions[1])!},\n });\n }\n}\n\n/** Shared post-pivot tail for BOTH the text and streaming Spectronaut paths.\n *\n * Builds the wide DataFrame, derives the primary protein column, detects/applies\n * the log2 transform, sets the `proteomics.*` tags, and auto-populates the two\n * experimental groups. `parseSpectronautText` and `parseSpectronautStream` both\n * end by handing their `PivotResult` here, so their output is byte-identical in\n * shape, semTypes, log2 columns, tags, and groups (R3).\n *\n * NOTE: this is the verbatim former tail of `parseSpectronautText` extracted\n * unchanged — do not edit tag strings, semType assignments, the log2 branch, or\n * column construction here without re-locking the existing Spectronaut tests. */\nasync function finalizeSpectronaut(result: PivotResult): Promise<DG.DataFrame> {\n // Build wide DataFrame\n const df = buildWideDataFrame(result);\n\n // Parse semicolon-delimited protein groups into primary column\n addPrimaryColumnIfNeeded(df, 'PG.ProteinGroups', 'Primary Protein ID', SEMTYPE.PROTEIN_ID);\n\n // Get intensity column names (the sample columns)\n const intensityColNames = result.sampleKeys;\n\n // Detect log2 status\n const log2Status = detectLog2Status(df, intensityColNames);\n\n if (log2Status.isLog2) {\n // Pre-normalized: copy as log2 columns without transformation\n copyAsLog2Columns(df, intensityColNames);\n } else {\n // Raw: apply log2 transformation, keeping originals\n log2TransformColumns(df, intensityColNames);\n }\n\n // Spectronaut always performs its own normalization regardless of export format\n df.setTag('proteomics.preNormalized', 'true');\n\n // Tag source\n df.setTag('proteomics.source', 'spectronaut');\n\n // Auto-populate groups from R.Condition\n autoPopulateGroups(df, result.sampleKeys);\n\n await resolveGeneLabels(df);\n\n return df;\n}\n\n/** Mirrors duckdb `nullstr=['','NaN','NA']` + `TRY_CAST(... AS DOUBLE)` from\n * tools/spectronaut-aggregate.sql. Returns `null` for the duckdb null tokens\n * and for anything that is not a finite number; otherwise the parsed number.\n *\n * This is intentionally STRICTER than `pivotSpectronaut`'s loose\n * `Number(raw)`/`isNaN` (which treats `''` as `0` via `Number('')`): the\n * streaming path must match the duckdb D-04 golden oracle exactly. The two\n * paths only diverge on degenerate inputs (`''` q-value/quantity) that the\n * real Spectronaut exports and the synthetic fixture never contain — the text\n * path stays byte-identical because it does not route precursor reports. */\nfunction tryCastDouble(s: string | null | undefined): number | null {\n if (s === null || s === undefined) return null;\n const t = s.trim();\n if (t === '' || t === 'NaN' || t === 'NA') return null;\n const n = Number(t);\n return Number.isFinite(n) ? n : null;\n}\n\n/** Outcome of feeding one already-split streamed data line to `handleFields`:\n *\n * - `'kept'` — the row was aggregated into `agg` (counts toward `rowCount`).\n * - `'malformed'` — the row is structurally unparseable (too few tab-separated\n * fields). ONLY this category is surfaced to the user as\n * \"malformed/unparseable line(s)\".\n * - `'filtered'` — the row was dropped by a correct, by-design duckdb-parity\n * filter (empty `PG.ProteinGroups`, CON__/REV__ decoy/\n * contaminant, numeric `EG.Qvalue` > threshold, or both\n * numeric casts null). This is NOT malformed and is SILENT —\n * exactly as the text path (`pivotSpectronaut`) is for the\n * identical drops.\n */\ntype LineOutcome = 'kept' | 'malformed' | 'filtered';\n\n/** Per-(protein × condition × replicate) running aggregate accumulated by the\n * streaming path. Mirrors the duckdb GROUP BY: `max(quantity)`, `min(qvalue)`,\n * first-non-null `R.FileName` / `PG.Organisms`. */\ninterface AggRow {\n protein: string;\n condition: string;\n replicate: string;\n maxQuantity: number;\n minQvalue: number;\n fileName: string | null;\n organism: string | null;\n}\n\n/** Group-key field separator. ASCII Unit Separator (0x1F) is not a TSV-legal\n * character, so it cannot collide with any condition/replicate/protein value. */\nconst AGG_KEY_SEP = '\\x1f';\n\n/** Folds the streaming aggregate map into the same `PivotResult` shape that\n * `pivotSpectronaut` produces, so `finalizeSpectronaut` is path-agnostic.\n * `sampleKey` MUST be `${condition}_${replicate}` to match `pivotSpectronaut`\n * (L65) and `autoPopulateGroups`'s `lastIndexOf('_')` split. */\nfunction aggToPivotResult(agg: Map<string, AggRow>): PivotResult {\n const proteinMap = new Map<string, Map<string, number>>();\n const sampleSet = new Set<string>();\n const sampleFileNames = new Map<string, string>();\n const organisms = new Map<string, string>();\n\n for (const row of agg.values()) {\n // Never-set groups (no surviving numeric quantity) carry -Infinity; skip\n // them exactly as duckdb would emit no quantity for an all-null group.\n if (!Number.isFinite(row.maxQuantity)) continue;\n\n const sampleKey = `${row.condition}_${row.replicate}`;\n sampleSet.add(sampleKey);\n\n if (!proteinMap.has(row.protein))\n proteinMap.set(row.protein, new Map<string, number>());\n proteinMap.get(row.protein)!.set(sampleKey, row.maxQuantity);\n\n if (row.fileName !== null && !sampleFileNames.has(sampleKey))\n sampleFileNames.set(sampleKey, row.fileName);\n if (row.organism !== null && !organisms.has(row.protein))\n organisms.set(row.protein, row.organism);\n }\n\n return {\n proteinMap,\n sampleKeys: Array.from(sampleSet).sort(),\n sampleFileNames,\n organisms,\n };\n}\n\n/** Streams a precursor/fragment-level Spectronaut long-format TSV `File` and\n * single-pass aggregates it down to the same wide protein-by-sample DataFrame\n * `parseSpectronautText` produces — without ever materializing the whole file\n * as a string (the V8 ~512 MB string ceiling is why a 2.6 GB report OOMs the\n * text path). Only state retained is the bounded carry-over line buffer and the\n * aggregate Map keyed by (protein × condition × replicate); raw input rows are\n * NEVER buffered (T-12-05).\n *\n * Filter / aggregate parity with tools/spectronaut-aggregate.sql:\n * - drop empty / `CON__` / `REV__` `PG.ProteinGroups`\n * - drop a row only if `tryCastDouble(EG.Qvalue) > threshold` (null/non-numeric\n * passes — duckdb `IS NULL OR <= 0.01`)\n * - per group: `max(tryCastDouble(quantity))`, `min(tryCastDouble(EG.Qvalue))`,\n * first-non-null `R.FileName` / `PG.Organisms`\n * - the DMD↔WT `R.Condition` flip in the SQL is REFERENCE-FILE-ONLY and is\n * deliberately NOT ported here (RESEARCH Pitfall 1).\n *\n * Malformed lines (too few fields, or both numeric casts null) are skipped and\n * counted (duckdb `ignore_errors=true` parity), surfaced via the progress\n * message rather than aborting. A `TaskBarProgressIndicator` advances by\n * bytes-read and an explicit `setTimeout(0)` macrotask yield runs on a ~16 ms\n * cadence so the tab stays responsive (T-12-09; the stream-read await alone\n * does not yield on OS-buffered data). */\nexport async function parseSpectronautStream(\n file: File, qValueThreshold: number = 0.01,\n): Promise<DG.DataFrame> {\n const pi = DG.TaskBarProgressIndicator.create('Streaming Spectronaut report...');\n try {\n const reader = file.stream()\n .pipeThrough(new TextDecoderStream('utf-8'))\n .getReader();\n\n const agg = new Map<string, AggRow>();\n let buffer = '';\n let headerParsed = false;\n let colIdx: Map<string, number> = new Map();\n let protI = -1; let condI = -1; let repI = -1;\n let qvalI = -1; let qtyI = -1; let fileI = -1; let orgI = -1;\n // Phase 16 SPC seed (D-01) — OPTIONAL columns, never required.\n let runDateI = -1; let instrMethodI = -1;\n let expectedFields = 0;\n let earliestRunDateMs: number | null = null;\n let earliestRunDateIso: string | null = null;\n let firstInstrumentMethod: string | null = null;\n\n let bytesRead = 0;\n let rowCount = 0;\n // Structurally unparseable lines (too few tab-separated fields). ONLY this\n // counter feeds the user-facing \"malformed line(s)\" message.\n let malformed = 0;\n // Rows dropped by a correct by-design duckdb-parity filter (CON__/REV__ or\n // numeric q > threshold). Tracked for completeness but SILENT to the user —\n // the text path (pivotSpectronaut) drops the identical rows with no message.\n let filtered = 0;\n let lastYield = performance.now();\n const fileSize = Math.max(1, file.size);\n\n /** Aggregate one already-split data line into `agg` (parity with the\n * duckdb WHERE + GROUP BY). Returns a discriminated outcome:\n * `'malformed'` for a structurally unparseable row (too few tab-separated\n * fields), `'filtered'` for a correct by-design duckdb-parity drop (empty\n * `PG.ProteinGroups`, CON__/REV__ decoy/contaminant, numeric `EG.Qvalue` >\n * threshold, or both numeric casts null), `'kept'` once the row is\n * aggregated. Empty-protein and both-casts-null are duckdb-silent drops\n * that the text path (`pivotSpectronaut`) also drops without messaging —\n * categorizing them `'filtered'` keeps streaming↔text user-message parity.\n * The predicates below are duckdb-parity-correct and UNCHANGED — only the\n * outcome value carries the malformed-vs-filtered distinction. */\n const handleFields = (f: string[]): LineOutcome => {\n if (f.length < expectedFields) return 'malformed';\n const protein = f[protI];\n // Drop empty / decoy / contaminant protein groups — all silent, matching\n // `pivotSpectronaut`'s `if (!protein) continue` + CON__/REV__ skip.\n if (!protein) return 'filtered';\n if (protein.startsWith('CON__') || protein.startsWith('REV__')) return 'filtered';\n\n const q = qvalI >= 0 ? tryCastDouble(f[qvalI]) : null;\n // duckdb: (qvalue IS NULL OR qvalue <= threshold) — null/non-numeric pass.\n if (q !== null && q > qValueThreshold) return 'filtered';\n\n const qty = tryCastDouble(f[qtyI]);\n // Both numeric casts null → unusable for aggregation; drop silently\n // (duckdb `ignore_errors` semantics — the text path likewise omits this row).\n if (qty === null && q === null) return 'filtered';\n\n const condition = f[condI] ?? '';\n const replicate = f[repI] ?? '';\n const key = protein + AGG_KEY_SEP + condition + AGG_KEY_SEP + replicate;\n let row = agg.get(key);\n if (row === undefined) {\n row = {\n protein, condition, replicate,\n maxQuantity: -Infinity, minQvalue: Infinity,\n fileName: null, organism: null,\n };\n agg.set(key, row);\n }\n if (qty !== null && qty > row.maxQuantity) row.maxQuantity = qty;\n if (q !== null && q < row.minQvalue) row.minQvalue = q;\n if (row.fileName === null && fileI >= 0) {\n const fn = f[fileI];\n if (fn) row.fileName = fn;\n }\n if (row.organism === null && orgI >= 0) {\n const og = f[orgI];\n if (og) row.organism = og;\n }\n // Phase 16 SPC seed (D-01) — accumulate inline so the streaming-path adds\n // no second pass over the file.\n if (runDateI >= 0) {\n const rd = f[runDateI];\n if (rd) {\n const ms = tryParseRunDate(rd);\n if (ms !== null && (earliestRunDateMs === null || ms < earliestRunDateMs)) {\n earliestRunDateMs = ms;\n earliestRunDateIso = new Date(ms).toISOString();\n }\n }\n }\n if (instrMethodI >= 0 && firstInstrumentMethod === null) {\n const im = f[instrMethodI];\n if (im && im.trim().length > 0) firstInstrumentMethod = im;\n }\n return 'kept';\n };\n\n /** Parse the first complete line as the header; resolve column indices and\n * the single quantity column once, matching the text-path validation. */\n const parseHeader = (line: string): void => {\n const cols = line.split('\\t');\n colIdx = new Map();\n for (let i = 0; i < cols.length; i++)\n colIdx.set(cols[i], i);\n for (const colName of REQUIRED_COLUMNS) {\n if (!colIdx.has(colName))\n throw new Error(`Missing required Spectronaut column: ${colName}`);\n }\n const quantityColName = QUANTITY_COLUMNS.find((n) => colIdx.has(n));\n if (!quantityColName) {\n throw new Error(`Missing protein-group quantity column ` +\n `(expected one of ${QUANTITY_COLUMNS.join(', ')})`);\n }\n protI = colIdx.get('PG.ProteinGroups')!;\n condI = colIdx.get('R.Condition')!;\n repI = colIdx.get('R.Replicate')!;\n qtyI = colIdx.get(quantityColName)!;\n qvalI = colIdx.has('EG.Qvalue') ? colIdx.get('EG.Qvalue')! : -1;\n fileI = colIdx.has('R.FileName') ? colIdx.get('R.FileName')! : -1;\n orgI = colIdx.has('PG.Organisms') ? colIdx.get('PG.Organisms')! : -1;\n // Phase 16 SPC seed: optional indices, contribute to expectedFields ONLY\n // when present so v1.3 headers without them still parse.\n runDateI = colIdx.has('R.RunDate') ? colIdx.get('R.RunDate')! : -1;\n instrMethodI = colIdx.has('R.InstrumentMethod') ? colIdx.get('R.InstrumentMethod')! : -1;\n // Highest index we read; a shorter split means a truncated/malformed row.\n expectedFields = Math.max(\n protI, condI, repI, qtyI, qvalI, fileI, orgI, runDateI, instrMethodI,\n ) + 1;\n headerParsed = true;\n };\n\n while (true) {\n const {value, done} = await reader.read();\n if (done) break;\n bytesRead += value.length;\n buffer += value;\n\n let nl: number;\n while ((nl = buffer.indexOf('\\n')) >= 0) {\n let line = buffer.slice(0, nl);\n buffer = buffer.slice(nl + 1);\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n if (!headerParsed) {\n if (line.length === 0) continue;\n parseHeader(line);\n continue;\n }\n if (line.length === 0) continue;\n switch (handleFields(line.split('\\t'))) {\n case 'kept': rowCount++; break;\n case 'malformed': malformed++; break;\n case 'filtered': filtered++; break;\n }\n }\n\n // ~16 ms wall-clock yield cadence (RESEARCH Q3 resolution / D-02). The\n // explicit setTimeout(0) macrotask yield is REQUIRED — await reader.read()\n // does not reliably yield on OS-buffered data (T-12-09).\n const now = performance.now();\n if (now - lastYield >= 16) {\n const pct = Math.min(99, (bytesRead / fileSize) * 100);\n // Only the genuine-malformed count is surfaced; by-design-filtered rows\n // (CON__/REV__, q > threshold) stay silent — text-path-consistent.\n const msg = malformed > 0\n ? `${rowCount} rows (${malformed} malformed skipped)`\n : `${rowCount} rows`;\n pi.update(pct, msg);\n await new Promise<void>((r) => setTimeout(r, 0));\n lastYield = performance.now();\n }\n }\n\n // Flush a trailing partial line (file without a final newline).\n if (buffer.length > 0) {\n let line = buffer;\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n if (line.length > 0) {\n if (!headerParsed) {\n parseHeader(line);\n } else {\n switch (handleFields(line.split('\\t'))) {\n case 'kept': rowCount++; break;\n case 'malformed': malformed++; break;\n case 'filtered': filtered++; break;\n }\n }\n }\n }\n\n if (!headerParsed)\n throw new Error('Missing required Spectronaut column: R.Condition');\n\n // Genuine-malformed only. By-design-filtered rows (CON__/REV__, q >\n // threshold) are intentionally SILENT — pivotSpectronaut drops the\n // identical rows with no message; matching that silence is the locked,\n // path-consistent UX decision. `filtered` is tracked but never surfaced.\n void filtered;\n if (malformed > 0)\n grok.shell.info(`Spectronaut import: skipped ${malformed} malformed line(s)`);\n\n const pivot = aggToPivotResult(agg);\n pivot.earliestRunDate = earliestRunDateIso;\n pivot.firstInstrumentMethod = firstInstrumentMethod;\n const df = await finalizeSpectronaut(pivot);\n // Phase 16 D-01: write the `proteomics.spc_run_meta_seed` tag when either\n // capture was made (streaming path).\n applySpcRunMetaSeed(df, pivot);\n return df;\n } finally {\n pi.close();\n }\n}\n\n/** Parses Spectronaut long-format TSV text into a wide protein-by-sample DataFrame.\n *\n * Applies:\n * - Q-value filtering (default threshold 0.01; non-numeric q-values pass)\n * - CON__/REV__ contaminant/decoy filtering\n * - Long-to-wide pivot using PG.IBAQ (preferred) or PG.Quantity (newer exports)\n * as protein-level intensity\n * - Semantic type assignment (PROTEIN_ID, INTENSITY)\n * - Log2 transformation (or copy if pre-normalized)\n * - Auto-group population from R.Condition when exactly 2 conditions\n * - Pre-normalization detection and tagging */\nexport async function parseSpectronautText(text: string, qValueThreshold: number = 0.01): Promise<DG.DataFrame> {\n // Parse long-format TSV\n const longDf = DG.DataFrame.fromCsv(text, {delimiter: '\\t'});\n\n // Validate required columns\n for (const colName of REQUIRED_COLUMNS) {\n if (!longDf.col(colName))\n throw new Error(`Missing required Spectronaut column: ${colName}`);\n }\n\n // Pick the protein-group quantity column (PG.IBAQ preferred, PG.Quantity accepted).\n const quantityColName = QUANTITY_COLUMNS.find((n) => longDf.col(n) !== null);\n if (!quantityColName) {\n throw new Error(`Missing protein-group quantity column ` +\n `(expected one of ${QUANTITY_COLUMNS.join(', ')})`);\n }\n\n // Pivot long-to-wide with filtering\n const result = pivotSpectronaut(longDf, quantityColName, qValueThreshold);\n\n // Shared post-pivot tail (identical for the streaming path).\n const df = await finalizeSpectronaut(result);\n // Phase 16 D-01: write the `proteomics.spc_run_meta_seed` tag when either\n // capture was made (text path).\n applySpcRunMetaSeed(df, result);\n return df;\n}\n\n/** Phase 16 D-01: Attach the SPC run-meta seed to the parsed df when either\n * R.RunDate or R.InstrumentMethod was captured. Plan 16-05's Annotate\n * Experiment dialog reads this seed to prefill its two new inputs. */\nfunction applySpcRunMetaSeed(df: DG.DataFrame, result: PivotResult): void {\n const hasDate = result.earliestRunDate != null;\n const hasInstr = result.firstInstrumentMethod != null;\n if (!hasDate && !hasInstr) return;\n df.setTag('proteomics.spc_run_meta_seed', JSON.stringify({\n instrument_id: result.firstInstrumentMethod ?? '',\n acquisition_datetime: result.earliestRunDate ?? '',\n }));\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\nimport {awaitCheck, delay} from '@datagrok-libraries/test/src/test';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {findColumn} from '../utils/column-detection';\nimport {\n META_COLUMNS, PUBLISHED_TAGS, PublishedMetadata, getPublishedMetadata,\n} from './publish-state';\n\n/**\n * Load-bearing distinguishing marker. Plan 04 step 8's catch block matches on\n * this prefix to identify the \"look/filter config stripped by serializer\"\n * failure mode and trigger the post-open formula-line recovery hook (B-2 / W-7)\n * BEFORE rolling back the published Project.\n */\nexport const FORMULA_LINE_ASSERTION_PREFIX = 'FORMULA_LINE_MISSING:' as const;\n\n/** What the publisher claimed at publish time, used as the expected baseline\n * for {@link assertPublishedShape}. */\nexport interface PublishedShapeContract {\n /** The trimmed DF's name (e.g. `<source>_published_<YYYY-MM-DD>`). */\n expectedName: string;\n /** The Project's name (e.g. `Proteomics-Review-<slug>-v<N>-<YYYY-MM-DD>`). */\n expectedProjectName: string;\n /** The 7-or-fewer column names the trim chose. */\n expectedAllowlist: string[];\n expectedMeta: PublishedMetadata;\n /** Whether a volcano viewer should be present on reopen. */\n expectVolcano: boolean;\n /** Whether an enrichment DataFrame should be present in `grok.shell.tables`. */\n expectEnrichment: boolean;\n /** Whether FC/p threshold formula lines should be present on the volcano.\n * PUB-06 / SC-2 — defaults to true when `expectVolcano` is true. */\n expectFormulaLines: boolean;\n}\n\n/**\n * Reopens the saved Project in a fresh session and asserts every observable\n * invariant of the publish contract. Throws on first violation with a\n * specific error including which assertion failed and what was observed.\n *\n * Single source of truth: BOTH the Plan 04 orchestrator (step 8 non-negotiable\n * gate) AND the Plan 08 regression test (`src/tests/publish-roundtrip.ts`)\n * call this helper. If the contract changes, it changes here.\n *\n * The volcano-formula-line assertion (8a) throws an error PREFIXED with\n * {@link FORMULA_LINE_ASSERTION_PREFIX}. Plan 04 step 8 catches this specific\n * prefix to drive its self-healing recovery (W-7) — re-add the formula lines\n * from `proteomics.published_fc_threshold` / `proteomics.published_p_threshold`\n * tags and re-run this assertion exactly once before rolling back.\n *\n * Caller is responsible for `grok.shell.closeAll()` after the assertion if\n * additional cleanup is desired.\n */\nexport async function assertPublishedShape(\n project: DG.Project,\n contract: PublishedShapeContract,\n): Promise<void> {\n const projId = project.id;\n grok.shell.closeAll();\n await delay(100);\n\n const reopened = await grok.dapi.projects.find(projId);\n await reopened.open();\n\n await awaitCheck(\n () => !!grok.shell.tv && !!grok.shell.tv.dataFrame,\n 'assertPublishedShape: TableView never materialized after project.open()',\n 5000,\n );\n\n const reDf = grok.shell.tv!.dataFrame;\n\n // ASSERTION 1 — df.name matches\n if (reDf.name !== contract.expectedName) {\n throw new Error(\n `assertPublishedShape: df.name: got \"${reDf.name}\", expected \"${contract.expectedName}\"`);\n }\n\n // ASSERTION 2 — Project name matches (PUB-09)\n if ((reopened as any).name !== contract.expectedProjectName) {\n throw new Error(\n `assertPublishedShape: project.name: got \"${(reopened as any).name}\", expected \"${contract.expectedProjectName}\"`);\n }\n\n // ASSERTION 3 — Every allowlist column present\n for (const colName of contract.expectedAllowlist) {\n if (!reDf.col(colName)) {\n throw new Error(\n `assertPublishedShape: allowlist column missing on reopen: \"${colName}\"`);\n }\n }\n\n // ASSERTION 4 — Column count matches allowlist (no extras except hidden\n // _meta_* belt-and-braces columns and ~-prefixed technical columns such as\n // the volcano's '~Volcano label' — neither is part of the published shape).\n const visibleCols = reDf.columns.toList()\n .map((c) => c.name)\n .filter((n) => !n.startsWith('_meta_') && !n.startsWith('~'));\n if (visibleCols.length !== contract.expectedAllowlist.length) {\n const unexpected = visibleCols.filter((n) => !contract.expectedAllowlist.includes(n));\n const missing = contract.expectedAllowlist.filter((n) => !visibleCols.includes(n));\n throw new Error(\n `assertPublishedShape: visible column count: got ${visibleCols.length}, expected ${contract.expectedAllowlist.length}. ` +\n `Unexpected: [${unexpected.join(', ')}]. Missing: [${missing.join(', ')}].`);\n }\n\n // ASSERTION 5 — PROTEIN_ID semType present on protein-id column\n const proteinIdCol = findColumn(reDf, SEMTYPE.PROTEIN_ID, ['protein id', 'majority protein id', 'accession']);\n if (proteinIdCol == null) {\n throw new Error('assertPublishedShape: protein-id column not found via findColumn');\n }\n if (proteinIdCol.semType !== SEMTYPE.PROTEIN_ID) {\n throw new Error(\n `assertPublishedShape: protein-id semType: got \"${proteinIdCol.semType ?? 'null'}\", ` +\n `expected \"${SEMTYPE.PROTEIN_ID}\". Detectors may not have re-fired on reopen — ` +\n `re-assign in trim-dataframe.ts Step E.`);\n }\n\n // ASSERTION 6 — Required proteomics.published* metadata readable (column FIRST, tag SECOND)\n const meta = getPublishedMetadata(reDf);\n if (meta == null) {\n throw new Error(\n 'assertPublishedShape: getPublishedMetadata returned null — published flag ' +\n 'not set or all critical fields unreadable');\n }\n const expectedMeta = contract.expectedMeta;\n const eqFloat = (a: number, b: number) => !(Math.abs(a - b) > 1e-9);\n if (meta.target !== expectedMeta.target)\n throw new Error(`assertPublishedShape: meta.target: got \"${meta.target}\", expected \"${expectedMeta.target}\"`);\n if (meta.deMethod !== expectedMeta.deMethod)\n throw new Error(`assertPublishedShape: meta.deMethod: got \"${meta.deMethod}\", expected \"${expectedMeta.deMethod}\"`);\n if (!eqFloat(meta.fcThreshold, expectedMeta.fcThreshold))\n throw new Error(`assertPublishedShape: meta.fcThreshold: got ${meta.fcThreshold}, expected ${expectedMeta.fcThreshold}`);\n if (!eqFloat(meta.pThreshold, expectedMeta.pThreshold))\n throw new Error(`assertPublishedShape: meta.pThreshold: got ${meta.pThreshold}, expected ${expectedMeta.pThreshold}`);\n if (meta.version !== expectedMeta.version)\n throw new Error(`assertPublishedShape: meta.version: got ${meta.version}, expected ${expectedMeta.version}`);\n if (meta.publishId !== expectedMeta.publishId)\n throw new Error(`assertPublishedShape: meta.publishId: got \"${meta.publishId}\", expected \"${expectedMeta.publishId}\"`);\n if (meta.includesEnrichment !== expectedMeta.includesEnrichment)\n throw new Error(`assertPublishedShape: meta.includesEnrichment: got ${meta.includesEnrichment}, expected ${expectedMeta.includesEnrichment}`);\n if (meta.publishedBy !== expectedMeta.publishedBy)\n throw new Error(`assertPublishedShape: meta.publishedBy: got \"${meta.publishedBy}\", expected \"${expectedMeta.publishedBy}\"`);\n\n // ASSERTION 7 — Belt-and-braces metadata column present (PUB-11)\n for (const key of Object.keys(META_COLUMNS) as Array<keyof typeof META_COLUMNS>) {\n const colName = META_COLUMNS[key];\n if (!reDf.col(colName)) {\n throw new Error(`assertPublishedShape: metadata column missing: \"${colName}\"`);\n }\n }\n\n // ASSERTION 8 — Volcano viewer present (PUB-06)\n let volcanoViewer: DG.Viewer | null = null;\n if (contract.expectVolcano) {\n try {\n await awaitCheck(\n () => {\n const tv = grok.shell.tv;\n if (!tv) return false;\n for (const v of tv.viewers) {\n if (v.type === DG.VIEWER.SCATTER_PLOT) {\n volcanoViewer = v;\n return true;\n }\n }\n return false;\n },\n 'assertPublishedShape: volcano scatter plot not present on reopen — consider post-open recomputeVolcano in publish-project.ts',\n 5000,\n );\n } catch (e) {\n throw new Error(`assertPublishedShape: volcano viewer assertion failed: ${(e as Error)?.message ?? e}`);\n }\n }\n\n // ASSERTION 8a — Volcano formula lines for FC + p thresholds (PUB-06 / SC-2, B-2 / W-7)\n if (contract.expectVolcano && contract.expectFormulaLines && volcanoViewer != null) {\n const fcStr = String(expectedMeta.fcThreshold);\n const pStr = String(expectedMeta.pThreshold);\n const minusLogPStr = String(-Math.log10(expectedMeta.pThreshold));\n\n type FormulaLine = {formula?: string; title?: string};\n const collected: FormulaLine[] = [];\n\n try {\n const dfLines = ((reDf as any).meta?.formulaLines?.items ?? []) as FormulaLine[];\n if (Array.isArray(dfLines)) collected.push(...dfLines);\n } catch { /* fall through */ }\n try {\n const opts: any = (volcanoViewer as DG.Viewer).getOptions?.();\n const lookLines = opts?.look?.formulaLines;\n const parsed = typeof lookLines === 'string' ? JSON.parse(lookLines) : lookLines;\n if (Array.isArray(parsed)) collected.push(...(parsed as FormulaLine[]));\n } catch { /* fall through */ }\n try {\n const propLines = (volcanoViewer as any)?.props?.formulaLines;\n const parsed = typeof propLines === 'string' ? JSON.parse(propLines) : propLines;\n if (Array.isArray(parsed)) collected.push(...(parsed as FormulaLine[]));\n } catch { /* fall through */ }\n\n const formulas = collected\n .map((l) => (typeof l?.formula === 'string' ? l.formula : ''))\n .filter((f) => f.length > 0);\n\n const hasFcLine = formulas.some((f) => f.includes(fcStr) || f.includes(`-${fcStr}`));\n const hasPLine = formulas.some((f) => f.includes(minusLogPStr) || f.includes(pStr));\n\n if (!hasFcLine || !hasPLine) {\n throw new Error(\n `${FORMULA_LINE_ASSERTION_PREFIX} volcano reopened without formula lines for ` +\n `FC=${expectedMeta.fcThreshold} and/or p=${expectedMeta.pThreshold}. ` +\n `The look/filter config was stripped by the serializer (Phase 13 e527d07ba1 evidence). ` +\n `Plan 04 step 8 catch should invoke the post-open recovery hook from tags ` +\n `${PUBLISHED_TAGS.PUBLISHED_FC_THRESHOLD} / ${PUBLISHED_TAGS.PUBLISHED_P_THRESHOLD} ` +\n `and re-run this assertion once.`);\n }\n }\n\n // ASSERTION 9 — Enrichment DF presence (PUB-12, conditional)\n if (contract.expectEnrichment) {\n const tables = (grok.shell as any).tables as DG.DataFrame[] | undefined;\n if (!Array.isArray(tables) || tables.length < 2) {\n throw new Error(\n `assertPublishedShape: expectEnrichment=true but grok.shell.tables has ${tables?.length ?? 0} DataFrames (need ≥ 2)`);\n }\n const proteinDf = tables.find((d) => {\n try {\n const col = d.col(META_COLUMNS.PUBLISHED_INCLUDES_ENRICHMENT);\n return col != null && String(col.get(0)) === 'true';\n } catch { return false; }\n });\n if (!proteinDf)\n throw new Error('assertPublishedShape: protein DF (with _meta_published_includes_enrichment=true) not found among reopened tables');\n const enrichDf = tables.find((d) => d.getTag('proteomics.enrichment') === 'true');\n if (!enrichDf)\n throw new Error('assertPublishedShape: enrichment DF (proteomics.enrichment=true tag) not found among reopened tables');\n }\n\n // ASSERTION 10 — Project options bidirectional supersede pointers (PUB-10, conditional)\n const opts: any = (reopened as any).options ?? {};\n if (expectedMeta.supersedes != null) {\n const got = opts[PUBLISHED_TAGS.SUPERSEDES];\n if (got !== expectedMeta.supersedes) {\n throw new Error(\n `assertPublishedShape: project.options['${PUBLISHED_TAGS.SUPERSEDES}']: got \"${got ?? 'null'}\", ` +\n `expected \"${expectedMeta.supersedes}\"`);\n }\n }\n if (expectedMeta.supersededBy != null) {\n const got = opts[PUBLISHED_TAGS.SUPERSEDED_BY];\n if (got !== expectedMeta.supersededBy) {\n throw new Error(\n `assertPublishedShape: project.options['${PUBLISHED_TAGS.SUPERSEDED_BY}']: got \"${got ?? 'null'}\", ` +\n `expected \"${expectedMeta.supersededBy}\"`);\n }\n }\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {PUBLISHED_TAGS, isPublished} from './publish-state';\nimport {applyVolcanoFormulaLines} from './publish-project';\nimport {wireEnrichmentToVolcano} from '../viewers/enrichment-viewers';\n\nconst ENRICHMENT_WIRED_TAG = 'proteomics.enrichment_wired';\n\n/**\n * Post-open recovery hook for reopened published Projects. Idempotent — safe\n * to call multiple times on the same DataFrame.\n *\n * Self-heals two failure modes:\n *\n * - **B-2 / W-7 — volcano formula lines stripped by serializer.** Reads FC\n * and p threshold values from the `proteomics.published_fc_threshold` /\n * `proteomics.published_p_threshold` tags (Plan 02's belt-and-braces #2\n * write via `setPublishedTags`) and re-applies via the exported\n * {@link applyVolcanoFormulaLines}. No-op when formula lines are already\n * present.\n *\n * - **W-5 — enrichment cross-DF highlight subscription not re-established\n * on reopen.** When the published Project carries both the protein DF\n * AND a published enrichment DF (both tagged `proteomics.published=true`),\n * wires the existing `wireEnrichmentToVolcano` subscription pattern from\n * `src/viewers/enrichment-viewers.ts`. Sentinel-tag duplicate-guard\n * (`proteomics.enrichment_wired`) prevents double subscriptions when the\n * user reopens the project repeatedly in one session.\n */\nexport async function recoverPublishedProject(df: DG.DataFrame): Promise<void> {\n if (!isPublished(df)) return;\n\n // PART 1 — Re-apply formula lines on the volcano (B-2 / W-7)\n const tv = findTableViewFor(df);\n if (tv) {\n const volcano = Array.from(tv.viewers).find((v) => v.type === DG.VIEWER.SCATTER_PLOT);\n if (volcano) {\n const fcRaw = df.getTag(PUBLISHED_TAGS.PUBLISHED_FC_THRESHOLD);\n const pRaw = df.getTag(PUBLISHED_TAGS.PUBLISHED_P_THRESHOLD);\n if (fcRaw && pRaw) {\n const fc = parseFloat(fcRaw);\n const p = parseFloat(pRaw);\n if (Number.isFinite(fc) && Number.isFinite(p)) {\n if (!hasFormulaLines(df, volcano)) {\n try { applyVolcanoFormulaLines(volcano, fc, p); } catch { /* best-effort */ }\n }\n }\n }\n }\n }\n\n // PART 2 — Re-establish enrichment cross-DF subscription (W-5)\n const enrichDf = findPublishedEnrichmentSibling(df);\n if (enrichDf && enrichDf.getTag(ENRICHMENT_WIRED_TAG) !== 'true') {\n try {\n wireEnrichmentToVolcano(enrichDf, df);\n enrichDf.setTag(ENRICHMENT_WIRED_TAG, 'true');\n } catch { /* best-effort */ }\n }\n}\n\nfunction findTableViewFor(df: DG.DataFrame): DG.TableView | null {\n try {\n const views = (grok.shell as any).tableViews as DG.TableView[] | undefined;\n if (Array.isArray(views)) {\n const match = views.find((v) => v?.dataFrame === df);\n if (match) return match;\n }\n } catch { /* fall through */ }\n try {\n const tv = grok.shell.tv;\n if (tv && tv.dataFrame === df) return tv;\n } catch { /* fall through */ }\n return null;\n}\n\nfunction hasFormulaLines(df: DG.DataFrame, viewer: DG.Viewer): boolean {\n try {\n const items = ((df as any).meta?.formulaLines?.items ?? []) as Array<{formula?: string}>;\n if (Array.isArray(items) && items.length > 0) return true;\n } catch { /* fall through */ }\n try {\n const opts: any = (viewer as any).getOptions?.();\n const lookLines = opts?.look?.formulaLines;\n if (typeof lookLines === 'string' && lookLines !== '' && lookLines !== '[]') return true;\n if (Array.isArray(lookLines) && lookLines.length > 0) return true;\n } catch { /* fall through */ }\n return false;\n}\n\nfunction findPublishedEnrichmentSibling(proteinDf: DG.DataFrame): DG.DataFrame | null {\n try {\n const tables = (grok.shell as any).tables as DG.DataFrame[] | undefined;\n if (!Array.isArray(tables)) return null;\n return tables.find((t) =>\n t !== proteinDf &&\n t?.getTag?.('proteomics.enrichment') === 'true' &&\n t?.getTag?.(PUBLISHED_TAGS.PUBLISHED) === 'true',\n ) ?? null;\n } catch {\n return null;\n }\n}\n","import * as DG from 'datagrok-api/dg';\n\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {findColumn, findProteomicsColumns} from '../utils/column-detection';\nimport {META_COLUMNS, PUBLISHED_TAGS, PublishedMetadata, setPublishedTags} from './publish-state';\n\n/**\n * Deep-clone + allowlist primitives that produce frozen DataFrame snapshots\n * ready for `DG.Project.save`. Pitfall 1 (stale-snapshot leak) and Pitfall 3\n * (tag-stripping serializer) are mitigated HERE, not in `publishAnalysis`.\n *\n * The orchestrator (Plan 04) never touches the source DataFrame directly — it\n * hands the source to {@link trimForPublish} and operates on the returned\n * clone. This is the only file in the package where `df.clone(...)` lives for\n * publishing.\n *\n * Spike 15-00 confirmed that `proteomics.*` tags and `Proteomics-*` semTypes\n * survive `DG.Project.save → find → open` on `release/1.27.3`, but does NOT\n * confirm they survive `df.clone(...)`. The defensive re-set is no-cost either\n * way — re-setting an already-present tag is idempotent.\n */\n\ninterface MetadataColumnSpec {\n name: string;\n value: string | number | Date | boolean | null;\n /** 'string' | 'datetime' | 'float' | 'int' — drives `columns.addNew*` */\n type: 'string' | 'datetime' | 'float' | 'int';\n /** When true, write '' (string) or 0 (numeric) instead of skipping null. */\n emptyForNull?: boolean;\n}\n\nfunction addMetadataColumn(df: DG.DataFrame, spec: MetadataColumnSpec): void {\n if (df.columns.contains(spec.name)) df.columns.remove(spec.name);\n let col: DG.Column;\n switch (spec.type) {\n case 'datetime':\n col = df.columns.addNewDateTime(spec.name);\n break;\n case 'float':\n col = df.columns.addNewFloat(spec.name);\n break;\n case 'int':\n col = df.columns.addNewInt(spec.name);\n break;\n case 'string':\n default:\n col = df.columns.addNewString(spec.name);\n break;\n }\n let constant: any;\n if (spec.value == null) {\n if (!spec.emptyForNull) return;\n constant = spec.type === 'string' ? '' : 0;\n } else if (spec.value instanceof Date) {\n constant = spec.value;\n } else if (typeof spec.value === 'boolean') {\n constant = spec.value ? 'true' : 'false';\n } else if (spec.type === 'string') {\n constant = String(spec.value);\n } else {\n constant = spec.value;\n }\n col.init(() => constant);\n col.setTag('.hidden', 'true');\n}\n\n/**\n * Returns a deep clone of `source` with only the protein-level allowlist\n * (Protein ID, Gene, log2FC, p-value, adj.p-value, significant, [direction])\n * + 13 belt-and-braces `_meta_*` columns + every required\n * `proteomics.published*` tag re-set explicitly. Source DataFrame is NOT\n * mutated. Throws on missing required columns (defensive — the Plan 07 menu\n * handler should have already gated via `requireDifferentialExpression`).\n */\nexport function trimForPublish(source: DG.DataFrame, meta: PublishedMetadata): DG.DataFrame {\n const cols = findProteomicsColumns(source);\n const proteinId = cols.proteinId;\n const geneName = cols.geneName;\n const log2fc = cols.log2fc;\n // 'adj.p-value' and 'p-value' both substring-match 'p-value'; resolve adj first\n // and then exclude its name when looking for the raw p-value column so the\n // allowlist doesn't end up with duplicates.\n const adjPValue = findColumn(source, '', ['adj.p-value', 'adj.p', 'fdr', 'q-value']);\n const pValue = source.columns.toList().find((c) => {\n const n = c.name.toLowerCase();\n return (n === 'p-value' || n === 'pvalue') && c.name !== (adjPValue?.name ?? '');\n }) ?? null;\n const significant = findColumn(source, '', ['significant', 'sig']);\n const direction = findColumn(source, '', ['direction', 'regulation', 'up_down']);\n\n const required: Array<[string, DG.Column | null]> = [\n ['Protein ID', proteinId],\n ['log2FC', log2fc],\n ['p-value', pValue],\n ['adj.p-value', adjPValue],\n ['significant', significant],\n ];\n for (const [label, col] of required) {\n if (col == null)\n throw new Error(`Cannot publish: missing required column [${label}]. Run Differential Expression to completion before publishing.`);\n }\n\n const allowlist: string[] = Array.from(new Set([\n proteinId!.name,\n geneName?.name,\n log2fc!.name,\n pValue!.name,\n adjPValue!.name,\n significant!.name,\n direction?.name,\n ].filter((n): n is string => typeof n === 'string' && n.length > 0)));\n\n const frozen = source.clone(null, allowlist);\n\n const carryForwardTags = [\n 'proteomics.source',\n 'proteomics.de_method',\n 'proteomics.groups',\n 'proteomics.de_complete',\n ];\n for (const k of carryForwardTags) {\n const v = source.getTag(k);\n if (v != null && v !== '') frozen.setTag(k, v);\n }\n\n setPublishedTags(frozen, meta);\n\n const dateSlice = meta.publishedAt instanceof Date\n ? meta.publishedAt.toISOString().slice(0, 10)\n : new Date(String(meta.publishedAt)).toISOString().slice(0, 10);\n frozen.name = `${source.name || 'analysis'}_published_${dateSlice}`;\n\n const semTypeAssignments: Array<[DG.Column | null, string]> = [\n [proteinId, SEMTYPE.PROTEIN_ID],\n [geneName, SEMTYPE.GENE_SYMBOL],\n [log2fc, SEMTYPE.LOG2FC],\n [pValue, SEMTYPE.P_VALUE],\n ];\n for (const [src, sem] of semTypeAssignments) {\n if (src == null) continue;\n const c = frozen.col(src.name);\n if (c != null) c.semType = sem;\n }\n\n const includesEnrichmentStr = meta.includesEnrichment ? 'true' : 'false';\n // Numeric metadata (FC / p threshold, version) stored as STRINGS to avoid\n // Float32 precision loss in `addNewFloat` (which is a single-precision\n // column type). The threshold values are exact doubles in the source meta;\n // string storage preserves them exactly, and `getPublishedMetadata` parses\n // them back via parseFloat / parseInt.\n const specs: MetadataColumnSpec[] = [\n {name: META_COLUMNS.PUBLISHED, value: 'true', type: 'string'},\n {name: META_COLUMNS.PUBLISHED_AT, value: meta.publishedAt, type: 'datetime'},\n {name: META_COLUMNS.PUBLISHED_BY, value: meta.publishedBy, type: 'string'},\n {name: META_COLUMNS.PUBLISHED_BY_EMAIL, value: meta.publishedByEmail ?? '', type: 'string', emptyForNull: true},\n {name: META_COLUMNS.PUBLISHED_TARGET, value: meta.target, type: 'string'},\n {name: META_COLUMNS.PUBLISHED_DE_METHOD, value: meta.deMethod, type: 'string'},\n {name: META_COLUMNS.PUBLISHED_FC_THRESHOLD, value: String(meta.fcThreshold), type: 'string'},\n {name: META_COLUMNS.PUBLISHED_P_THRESHOLD, value: String(meta.pThreshold), type: 'string'},\n {name: META_COLUMNS.PUBLISHED_VERSION, value: String(meta.version), type: 'string'},\n {name: META_COLUMNS.PUBLISHED_ID, value: meta.publishId, type: 'string'},\n {name: META_COLUMNS.PUBLISHED_INCLUDES_ENRICHMENT, value: includesEnrichmentStr, type: 'string'},\n {name: META_COLUMNS.SUPERSEDES, value: meta.supersedes ?? '', type: 'string', emptyForNull: true},\n {name: META_COLUMNS.SUPERSEDED_BY, value: meta.supersededBy ?? '', type: 'string', emptyForNull: true},\n ];\n for (const spec of specs)\n addMetadataColumn(frozen, spec);\n\n return frozen;\n}\n\n/**\n * Returns a deep clone of an enrichment DataFrame containing only the term /\n * source / p / adj.p / intersection allowlist (+ optional direction column\n * from the Phase 13 split). Called by the Plan 04 orchestrator opportunistically\n * (D-05): only when the source protein DataFrame carries\n * `proteomics.enrichment === 'true'` AND an enrichment DataFrame is present\n * in `grok.shell.tables`. If neither precondition holds, the orchestrator\n * skips this call entirely and the published Project ships protein-only.\n *\n * Throws on missing required columns. Direction column is soft: omitted from\n * the allowlist when absent rather than failing.\n */\nexport function trimEnrichmentForPublish(enrichSource: DG.DataFrame, meta: PublishedMetadata): DG.DataFrame {\n const term = findColumn(enrichSource, '', ['term name', 'term', 'pathway']);\n const sourceCol = findColumn(enrichSource, '', ['source']);\n // The g:Profiler producer (buildEnrichmentDf, enrichment.ts) emits ONE\n // FDR-corrected significance column named 'FDR' — there is no separate raw\n // p-value. Accept any single significance column (FDR / adj.p-value /\n // p-value) rather than requiring a p-value + adj.p-value pair that real\n // enrichment tables never carry.\n const sigCol = findColumn(enrichSource, '', ['fdr', 'adj.p-value', 'adj.p', 'q-value', 'p-value', 'pvalue']);\n const intersection = findColumn(enrichSource, '', ['intersection', 'genes']);\n const directionCol = findColumn(enrichSource, '', ['direction', 'regulation']);\n // Soft (omitted when absent): the published dot plot needs these to render\n // (x = Gene Ratio, size = Gene Count). Older enrichment frames may lack them.\n const geneRatioCol = findColumn(enrichSource, '', ['gene ratio']);\n const geneCountCol = findColumn(enrichSource, '', ['gene count']);\n\n const required: Array<[string, DG.Column | null]> = [\n ['Term Name', term],\n ['Source', sourceCol],\n ['significance (FDR / adj.p-value)', sigCol],\n ['Intersection', intersection],\n ];\n for (const [label, col] of required) {\n if (col == null)\n throw new Error(`Cannot publish enrichment: missing required column [${label}]. Re-run enrichment before publishing.`);\n }\n\n const allowlist: string[] = [\n term!.name,\n sourceCol!.name,\n sigCol!.name,\n intersection!.name,\n directionCol?.name,\n geneRatioCol?.name,\n geneCountCol?.name,\n ].filter((n): n is string => typeof n === 'string' && n.length > 0);\n\n const enrichClone = enrichSource.clone(null, allowlist);\n enrichClone.setTag('proteomics.enrichment', 'true');\n\n const dateSlice = meta.publishedAt instanceof Date\n ? meta.publishedAt.toISOString().slice(0, 10)\n : new Date(String(meta.publishedAt)).toISOString().slice(0, 10);\n enrichClone.name = `enrichment_published_${dateSlice}`;\n\n addMetadataColumn(enrichClone, {\n name: META_COLUMNS.PUBLISHED_ID,\n value: meta.publishId,\n type: 'string',\n });\n addMetadataColumn(enrichClone, {\n name: META_COLUMNS.PUBLISHED_INCLUDES_ENRICHMENT,\n value: 'true',\n type: 'string',\n });\n\n // Belt-and-braces tag so a reviewer reopening the enrichment DataFrame\n // alone can recover its provenance.\n enrichClone.setTag(PUBLISHED_TAGS.PUBLISHED, 'true');\n enrichClone.setTag(PUBLISHED_TAGS.PUBLISHED_ID, meta.publishId);\n enrichClone.setTag(PUBLISHED_TAGS.PUBLISHED_INCLUDES_ENRICHMENT, 'true');\n\n return enrichClone;\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\nimport {awaitCheck, delay} from '@datagrok-libraries/test/src/test';\n\nimport {\n META_COLUMNS, PUBLISHED_TAGS, PublishOptions, PublishedMetadata,\n slugifyTarget,\n} from './publish-state';\nimport {trimEnrichmentForPublish, trimForPublish} from './trim-dataframe';\nimport {\n FORMULA_LINE_ASSERTION_PREFIX, PublishedShapeContract, assertPublishedShape,\n} from './assert-published-shape';\nimport {createVolcanoPlot} from '../viewers/volcano';\nimport {dockEnrichmentCharts, openEnrichmentVisualization} from '../viewers/enrichment-viewers';\nimport {reviewSpaceName, reviewNamePrefix, verifyPublishedDashboard} from './publish-settings';\nimport {DEFAULT_FC_THRESHOLD, DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\n\n/**\n * Pure helper: applies (or replaces) the volcano threshold formula lines on\n * the DataFrame attached to {@link viewer}. Writes to `df.meta.formulaLines`\n * since that is where `applyThresholdLines` in `src/viewers/volcano.ts` stores\n * them (the platform's canonical location for scatter-plot formula lines).\n *\n * Exported so Plan 07's post-open recovery hook can re-apply the lines on a\n * reopened published Project's volcano when the serializer strips look config\n * (Phase 13 e527d07ba1 evidence). Idempotent — removes existing FC/y-axis\n * threshold lines before re-adding so repeat calls do not stack.\n */\nexport function applyVolcanoFormulaLines(\n viewer: DG.Viewer,\n fcThreshold: number,\n pThreshold: number,\n): void {\n const df = (viewer as any).dataFrame as DG.DataFrame | undefined;\n if (!df) return;\n\n let yColName: string | null = null;\n try {\n const opts: any = (viewer as any).getOptions?.();\n yColName = opts?.look?.yColumnName ?? null;\n } catch { /* fall through */ }\n if (!yColName) {\n try { yColName = (viewer as any).props?.yColumnName ?? null; } catch { /* fall through */ }\n }\n if (!yColName) return;\n\n const yPrefix = `\\${${yColName}}`;\n const fcPrefix = '${log2FC}';\n const hLine = -Math.log10(pThreshold);\n\n const meta: any = (df as any).meta;\n const formulaLines: any = meta?.formulaLines;\n if (!formulaLines) return;\n\n try {\n const items: any[] = Array.isArray(formulaLines.items) ? formulaLines.items : [];\n formulaLines.items = items.filter((line: any) => {\n const f = line?.formula ?? '';\n return !(typeof f === 'string' && (f.startsWith(yPrefix) || f.startsWith(fcPrefix)));\n });\n } catch { /* best effort */ }\n\n try {\n formulaLines.addLine({formula: `${yPrefix} = ${hLine}`, color: '#888888', width: 1, visible: true});\n formulaLines.addLine({formula: `${fcPrefix} = ${fcThreshold}`, color: '#888888', width: 1, visible: true});\n formulaLines.addLine({formula: `${fcPrefix} = ${-fcThreshold}`, color: '#888888', width: 1, visible: true});\n } catch { /* best effort */ }\n\n try { (viewer as any).props.showViewerFormulaLines = true; } catch { /* best effort */ }\n}\n\nfunction parsePriorVersion(priorName: string | null | undefined): number {\n if (!priorName) return 0;\n const m = /-v(\\d+)-/.exec(priorName);\n if (!m) return 0;\n const n = parseInt(m[1], 10);\n return Number.isFinite(n) ? n : 0;\n}\n\nfunction generateUuid(): string {\n try {\n const c = (globalThis as any)?.crypto;\n if (c && typeof c.randomUUID === 'function') return c.randomUUID();\n } catch { /* fall through */ }\n // RFC4122 v4 fallback\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Orchestrates the read-only publish flow. Source DataFrame is NEVER mutated\n * (Pitfall 1 / T-15-02 guarantee — Plan 02's `trimForPublish` owns the clone\n * boundary). Two non-negotiable gates: Step 7 verifies reviewer-group ACL via\n * `permissions.get` and rolls back on Edit-leak; Step 8 calls\n * {@link assertPublishedShape} against the reopened Project and rolls back on\n * contract violation — with a one-shot W-7 self-heal pass for the\n * formula-line-stripped failure mode.\n *\n * Publish-side belt-and-braces for PUB-06 / SC-2 formula lines:\n * #1 (this orchestrator, step 6.5) — apply formula lines on the trimmed\n * volcano BEFORE saving the view\n * #2 (Plan 01 setPublishedTags via Plan 02 trimForPublish) — persist FC and\n * p threshold values as `proteomics.published_fc_threshold` /\n * `proteomics.published_p_threshold` tags on the trimmed DataFrame so\n * the recovery hook can re-apply them later\n * #3 (Plan 07 post-open recovery hook) — re-apply formula lines from the\n * tags on reopen if the serializer stripped them; reuses the exported\n * {@link applyVolcanoFormulaLines} helper\n *\n * Per spike 15-00 (`15-00-SUMMARY.md`):\n * - A1: `permissions.get` returns `[\"view\", \"edit\"]` keys only (no share/delete)\n * - A2: Space-inheritance grants do NOT propagate to `permissions.get(project)`\n * → Step 7 grants View directly on the Project, not via the parent Space\n * - A4: `project.options[*]` survives round-trip → supersede pointer uses options\n */\nexport async function publishAnalysis(df: DG.DataFrame, opts: PublishOptions): Promise<DG.Project> {\n const pi = DG.TaskBarProgressIndicator.create('Publishing snapshot...');\n try {\n // ─── Step 1 — assemble PublishedMetadata (server-authoritative identity) ────\n pi.description = 'Preparing metadata...';\n const publishedBy = (grok.shell.user as any)?.friendlyName ?? '';\n const publishedByEmail = (grok.shell.user as any)?.email ?? null;\n const deMethod = (df.getTag('proteomics.de_method') ?? 't-test') as PublishedMetadata['deMethod'];\n\n let fcThreshold = DEFAULT_FC_THRESHOLD;\n let pThreshold = DEFAULT_P_THRESHOLD;\n try {\n const optsAny = opts as any;\n if (typeof optsAny.fcThreshold === 'number' && Number.isFinite(optsAny.fcThreshold))\n fcThreshold = optsAny.fcThreshold;\n if (typeof optsAny.pThreshold === 'number' && Number.isFinite(optsAny.pThreshold))\n pThreshold = optsAny.pThreshold;\n } catch { /* defaults */ }\n\n const slug = slugifyTarget(opts.target);\n const priorVersionN = parsePriorVersion((opts.priorVersion as any)?.name);\n const version = priorVersionN > 0 ? priorVersionN + 1 : 1;\n const publishId = generateUuid();\n const publishedAt = new Date();\n const dateStr = publishedAt.toISOString().slice(0, 10);\n\n const enrichSource: DG.DataFrame | null = (() => {\n const tables = (grok.shell as any).tables as DG.DataFrame[] | undefined;\n if (!Array.isArray(tables)) return null;\n return tables.find((t) => t.getTag('proteomics.enrichment') === 'true') ?? null;\n })();\n\n const meta: PublishedMetadata = {\n target: opts.target,\n publishedAt,\n publishedBy,\n publishedByEmail,\n deMethod,\n fcThreshold,\n pThreshold,\n version,\n publishId,\n includesEnrichment: !!enrichSource,\n supersedes: opts.priorVersion?.id ?? null,\n supersededBy: null,\n };\n\n // ─── Step 2 — trim protein DF (Pitfall 1: source not mutated) ────────────────\n pi.description = 'Trimming snapshot...';\n const frozen = trimForPublish(df, meta);\n const expectedName = frozen.name;\n\n // ─── Step 3 — opportunistic enrichment trim (D-05) ──────────────────────────\n let frozenEnrich: DG.DataFrame | null = null;\n if (enrichSource) {\n pi.description = 'Trimming enrichment...';\n frozenEnrich = trimEnrichmentForPublish(enrichSource, meta);\n }\n\n // ─── Step 4 — ensure umbrella Space (opts.umbrellaName override supported) ──\n pi.description = 'Ensuring umbrella Space...';\n const umbrellaName = opts.umbrellaName ?? reviewSpaceName();\n const dapiAny = grok.dapi as any;\n let umbrella: any = null;\n\n // Try create-first; if the Space already exists, fall back to enumeration.\n // The Datagrok smart-filter API does not reliably surface Space-flagged\n // Projects via `dapi.projects.filter(... and isSpace = true).first()`,\n // so we rely on `spaces.list()` enumeration as the lookup path.\n try {\n umbrella = await dapiAny.spaces.createRootSpace(umbrellaName);\n } catch (createErr: any) {\n const msg = String(createErr?.message ?? createErr ?? '');\n if (!/already exists|exists/i.test(msg)) throw createErr;\n try {\n const all: any[] = await dapiAny.spaces.list();\n umbrella = (all ?? []).find((p) =>\n p?.name === umbrellaName || (p as any)?.friendlyName === umbrellaName) ?? null;\n } catch { /* fall through */ }\n if (!umbrella) {\n throw new Error(\n `Umbrella Space '${umbrellaName}' exists on the server but could not be resolved ` +\n `by name from spaces.list() (msg: ${msg}). Ask an admin to inspect the conflicting Space.`);\n }\n }\n const umbrellaClient = dapiAny.spaces.id(umbrella.id);\n\n // ─── Step 5 — ensure per-target child Space ─────────────────────────────────\n pi.description = 'Ensuring per-target Space...';\n const childName = `${reviewNamePrefix()}-${slug}`;\n let childSpace: any = null;\n\n const findChildByName = async (): Promise<any> => {\n try {\n const kids: any[] = await umbrellaClient.children.filter('Project', false).list();\n return (kids ?? []).find((k) =>\n k?.friendlyName === childName || k?.name === childName) ?? null;\n } catch { return null; }\n };\n\n try {\n if (await umbrellaClient.subspaceExists(childName)) {\n childSpace = await findChildByName();\n }\n } catch { /* fall through to addSubspace */ }\n\n if (!childSpace) {\n try {\n childSpace = await umbrellaClient.addSubspace(childName);\n } catch (subErr: any) {\n const msg = String(subErr?.message ?? subErr ?? '');\n if (!/already exists|exists/i.test(msg)) throw subErr;\n childSpace = await findChildByName();\n if (!childSpace) {\n throw new Error(\n `Per-target child Space '${childName}' exists but could not be resolved via ` +\n `umbrella children.list() (msg: ${msg}).`);\n }\n }\n }\n const childClient = dapiAny.spaces.id(childSpace.id);\n\n // ─── Step 6 — create Project + addChild ─────────────────────────────────────\n pi.description = 'Saving Project...';\n const project = DG.Project.create();\n const projectName = `${reviewNamePrefix()}-${slug}-v${version}-${dateStr}`;\n (project as any).name = projectName;\n // Set friendlyName explicitly so the platform doesn't \"humanize\" the slug\n // (e.g. DMD → \"DM D\"). Use the original target verbatim for a clean label,\n // and derive the label's leading words from the (configurable) name prefix.\n (project as any).friendlyName =\n `${reviewNamePrefix().replace(/-/g, ' ')} ${opts.target} v${version} ${dateStr}`;\n\n try { (project as any).options[PUBLISHED_TAGS.PUBLISHED_ID] = publishId; } catch { /* swallow */ }\n // Step 9 writes the supersede pointer on the prior project; the NEW\n // project's `supersedes` pointer must be written BEFORE save so the\n // round-trip assertion in Step 8 sees it on reopen.\n if (opts.priorVersion != null) {\n try {\n (project as any).options[PUBLISHED_TAGS.SUPERSEDES] = (opts.priorVersion as any).id;\n } catch { /* swallow */ }\n }\n\n project.addChild(frozen.getTableInfo());\n if (frozenEnrich) project.addChild(frozenEnrich.getTableInfo());\n\n // ─── Step 6.5 — REVISION B-2: re-create volcano on trimmed DF + apply lines ─\n pi.description = 'Re-rendering volcano on trimmed snapshot...';\n const trimmedTv = grok.shell.addTableView(frozen);\n await delay(100);\n const volcano = createVolcanoPlot(frozen, {fcThreshold, pThreshold});\n trimmedTv.addViewer(volcano);\n applyVolcanoFormulaLines(volcano, fcThreshold, pThreshold);\n await delay(100);\n\n const viewInfo = trimmedTv.getInfo();\n project.addChild(viewInfo);\n\n // ─── Step 6.6 — re-create the enrichment Up/Down 2×2 on the published\n // enrichment view. The charts bind to frozenEnrich itself (dockEnrichmentCharts\n // adds the derived negLog10FDR / ~enrichChartTop columns onto it and splits\n // Up/Down via per-viewer formula filters), so there are no chart-backing\n // subset tables to bundle — the enrichment frame is fully self-contained and\n // the charts survive the project round-trip. ─────────────────────────────\n let enrichViewInfo: any = null;\n if (frozenEnrich) {\n pi.description = 'Re-rendering enrichment charts...';\n const enrichTv = grok.shell.addTableView(frozenEnrich);\n await delay(100);\n dockEnrichmentCharts(enrichTv, frozenEnrich);\n await delay(100);\n enrichViewInfo = enrichTv.getInfo();\n project.addChild(enrichViewInfo);\n // Land the user (and downstream readers of grok.shell.tv) back on the\n // protein/volcano view — the primary deliverable — not the enrichment tab.\n grok.shell.v = trimmedTv;\n }\n\n await grok.dapi.tables.uploadDataFrame(frozen);\n await grok.dapi.tables.save(frozen.getTableInfo());\n if (frozenEnrich) {\n // Upload AFTER dockEnrichmentCharts so the derived chart columns persist.\n await grok.dapi.tables.uploadDataFrame(frozenEnrich);\n await grok.dapi.tables.save(frozenEnrich.getTableInfo());\n }\n await grok.dapi.views.save(viewInfo);\n if (enrichViewInfo) await grok.dapi.views.save(enrichViewInfo);\n await grok.dapi.projects.save(project);\n // meta.publishId stays at the originally-generated UUID — it identifies the\n // *publish event* in the DataFrame's tag/column, distinct from project.id\n // (the Datagrok entity id). Step 9 supersede pointers use project.id directly.\n\n try { await childClient.addEntity(project.id); } catch (mvErr: any) {\n // Project move to child Space failed — surface but do not abort, since\n // the verify-and-rollback gate below grants directly on the Project\n // (not via Space inheritance per spike A2).\n grok.shell.warning(\n `Could not move Project into child Space \"${childName}\": ${mvErr?.message ?? mvErr}. ` +\n `Continuing — reviewer view grant is applied directly to the Project.`);\n }\n\n // ─── Step 7a — grant View directly on the Project (spike A2 — inheritance not visible) ──\n pi.description = 'Granting reviewer view-only access...';\n try {\n await grok.dapi.permissions.grant(project, opts.reviewerGroup, false);\n } catch (grantErr: any) {\n try { await grok.dapi.projects.delete(project); } catch (rb: any) {\n grok.shell.error(`Manual cleanup required: project id ${project.id} could not be deleted: ${rb?.message ?? rb}`);\n }\n throw new Error(`Reviewer group view grant failed: ${grantErr?.message ?? grantErr}`);\n }\n\n // ─── Step 7b — verify-and-rollback gate (T-15-01, NON-NEGOTIABLE) ───────────\n // Spike A2: `permissions.get(project)` does NOT surface Space-inherited grants.\n // So we check three rings: project, child Space, umbrella Space. Any Edit/Share/\n // Delete on the reviewer group at any level is a leak that fails the gate.\n pi.description = 'Verifying view-only access...';\n const reviewerId = (opts.reviewerGroup as any)?.id;\n const matchesGroup = (g: any): boolean => {\n if (g == null) return false;\n if (typeof g === 'string') return g === reviewerId;\n if (g?.id != null) return g.id === reviewerId;\n return false;\n };\n\n const projPerm: any = await grok.dapi.permissions.get(project);\n let childSpacePerm: any = null;\n let umbrellaPerm: any = null;\n try { if (childSpace) childSpacePerm = await grok.dapi.permissions.get(childSpace); } catch { /* swallow */ }\n try { if (umbrella) umbrellaPerm = await grok.dapi.permissions.get(umbrella); } catch { /* swallow */ }\n\n const inAny = (key: string): boolean => {\n for (const perm of [projPerm, childSpacePerm, umbrellaPerm]) {\n const arr = (perm as any)?.[key];\n if (Array.isArray(arr) && arr.some(matchesGroup)) return true;\n }\n return false;\n };\n\n const inView = inAny('view');\n const inEdit = inAny('edit');\n const inShare = inAny('share');\n const inDelete = inAny('delete');\n\n if (!inView || inEdit || inShare || inDelete) {\n try { await grok.dapi.projects.delete(project); } catch (rb: any) {\n grok.shell.error(`Manual cleanup required: project id ${project.id} could not be deleted: ${rb?.message ?? rb}`);\n }\n throw new Error(\n 'Reviewer group already has elevated access via Space inheritance — ' +\n 'publish aborted; ask an admin to scope the umbrella Space\\'s permissions');\n }\n\n // ─── Step 8 — round-trip verification (optional; `verifyPublishedDashboard`,\n // default ON) with W-7 self-heal on formula lines. This is the heavy part:\n // closeAll + reopen the project + assert it survives a reload. Keep it on for\n // client deliverables; turn it off for faster demo shares. The reviewer-access\n // verify-and-rollback gate (Step 7b) is separate and always runs. ────────────\n // Per-share checkbox (opts.verify) wins; fall back to the package setting for\n // non-dialog callers.\n if (opts.verify ?? verifyPublishedDashboard()) {\n pi.description = 'Verifying round-trip survival...';\n // expectedAllowlist captures the actual post-trim post-volcano column state\n // (volcano factory in step 6.5 adds derived columns like '-log10(adj.p-value)'),\n // not just the trim allowlist. The trim allowlist is the floor; the orchestrator\n // may add derived columns; the contract reflects what actually ships.\n // Exclude _meta_* belt-and-braces columns AND ~-prefixed technical columns\n // (e.g. the volcano's '~Volcano label') — assertPublishedShape ignores both\n // on the reopened side, so the expected list must too or the count mismatches.\n const expectedAllowlist = frozen.columns.toList()\n .map((c) => c.name)\n .filter((n) => !n.startsWith('_meta_') && !n.startsWith('~'));\n const contract: PublishedShapeContract = {\n expectedName,\n expectedProjectName: projectName,\n expectedAllowlist,\n expectedMeta: {...meta},\n expectVolcano: true,\n expectEnrichment: !!frozenEnrich,\n expectFormulaLines: true,\n };\n\n let healedOnce = false;\n while (true) {\n try {\n await assertPublishedShape(project, contract);\n break;\n } catch (assertErr: any) {\n const msg = String(assertErr?.message ?? assertErr ?? '');\n if (!healedOnce && msg.startsWith(FORMULA_LINE_ASSERTION_PREFIX)) {\n healedOnce = true;\n const tv = grok.shell.tv;\n const reopenedVolcano = tv\n ? Array.from(tv.viewers).find((v) => v.type === DG.VIEWER.SCATTER_PLOT)\n : null;\n if (reopenedVolcano && tv) {\n const reDf = tv.dataFrame;\n const fcFromTag = parseFloat(reDf.getTag(PUBLISHED_TAGS.PUBLISHED_FC_THRESHOLD) ?? String(fcThreshold));\n const pFromTag = parseFloat(reDf.getTag(PUBLISHED_TAGS.PUBLISHED_P_THRESHOLD) ?? String(pThreshold));\n applyVolcanoFormulaLines(\n reopenedVolcano,\n Number.isFinite(fcFromTag) ? fcFromTag : fcThreshold,\n Number.isFinite(pFromTag) ? pFromTag : pThreshold,\n );\n try { await grok.dapi.views.save(tv.getInfo()); } catch { /* best-effort */ }\n await delay(100);\n continue;\n }\n }\n try { await grok.dapi.projects.delete(project); } catch (rb: any) {\n grok.shell.error(`Manual cleanup required: project id ${project.id} could not be deleted: ${rb?.message ?? rb}`);\n }\n throw new Error(`Round-trip shape verification failed: ${assertErr?.message ?? assertErr}`);\n }\n }\n }\n\n // ─── Step 9 — supersede chain (D-04 + W-8 dual-write, non-destructive) ──────\n if (opts.priorVersion != null) {\n pi.description = 'Updating supersede chain...';\n const priorProjectId = (opts.priorVersion as any).id;\n try {\n const priorReloaded = await grok.dapi.projects.find(priorProjectId);\n (priorReloaded as any).options[PUBLISHED_TAGS.SUPERSEDED_BY] = project.id;\n await grok.dapi.projects.save(priorReloaded);\n } catch (priorOptsErr: any) {\n grok.shell.warning(\n `Supersede pointer on prior version's options failed: ${priorOptsErr?.message ?? priorOptsErr} ` +\n `(DataFrame-tag dual-write path below provides fallback).`);\n }\n\n try {\n grok.shell.closeAll();\n await delay(100);\n const priorReopened = await grok.dapi.projects.find(priorProjectId);\n await priorReopened.open();\n await awaitCheck(\n () => !!grok.shell.tv && !!grok.shell.tv.dataFrame,\n 'supersede stamp: prior project DF did not materialize',\n 5000,\n );\n const priorDf = grok.shell.tv!.dataFrame;\n priorDf.setTag(PUBLISHED_TAGS.SUPERSEDED_BY, project.id);\n const supersededByCol = priorDf.col(META_COLUMNS.SUPERSEDED_BY);\n if (supersededByCol) {\n try { supersededByCol.set(0, project.id); } catch { /* best-effort */ }\n }\n await grok.dapi.tables.uploadDataFrame(priorDf);\n await grok.dapi.tables.save(priorDf.getTableInfo());\n } catch (stampErr: any) {\n grok.shell.warning(\n `Supersede tag could not be stamped on prior version DF: ${stampErr?.message ?? stampErr} ` +\n `(Project.options pointer was still written — Plan 06 panel falls back to that path)`);\n }\n\n try { (project as any).options[PUBLISHED_TAGS.SUPERSEDES] = priorProjectId; } catch { /* swallow */ }\n try { await grok.dapi.projects.save(project); } catch (e) {\n grok.shell.warning(`Could not write supersedes pointer on new project options: ${(e as Error)?.message ?? e}`);\n }\n }\n\n // ─── Step 10 — restore the user's workspace ─────────────────────────────────\n // Round-trip verification (assertPublishedShape) does closeAll() + reopens the\n // published project to prove it survives a reload, and a self-heal step re-saves\n // a viewer (leaving that reopened project dirty → a SAVE badge). The supersede\n // path likewise closes everything and opens the PRIOR version. Either way the\n // user's original analysis is gone and the workspace is cluttered with\n // verification artifacts. Tear all that down and put them back on their source\n // analysis (table + volcano, plus the enrichment view + charts they had open);\n // the shared copy is one click away in the success dialog's \"Open shared analysis\".\n pi.description = 'Restoring your analysis...';\n try {\n grok.shell.closeAll();\n await delay(100);\n // Restore the enrichment results view + charts (and its volcano cross-link)\n // FIRST if the user had it open. openEnrichmentVisualization focuses the\n // enrichment tab; adding the protein view next lands the user back on the\n // volcano — the primary deliverable — with enrichment one tab away, exactly\n // as it was pre-publish. Uses enrichSource (the original untrimmed table),\n // not the trimmed publish copy.\n if (enrichSource) {\n try { openEnrichmentVisualization(enrichSource, df); } catch { /* best-effort */ }\n }\n const restoredTv = grok.shell.addTableView(df);\n try {\n restoredTv.addViewer(createVolcanoPlot(df));\n } catch { /* volcano is best-effort — the table view is what matters */ }\n } catch { /* restore is best-effort — never fail a successful publish on cleanup */ }\n\n pi.description = 'Done.';\n // No toast here — the share-dialog caller emits the single user-facing\n // confirmation, so publishing stays quiet to avoid a duplicate.\n return project;\n } finally {\n pi.close();\n }\n}\n","/**\n * Configurable destination for shared review snapshots.\n *\n * Both values are package settings (declared in `package.json` under `properties`, edited\n * from the package's **Settings** panel in the platform). They are read at share time, so\n * an admin can retarget where reviews land without a code change.\n *\n * What is and isn't configurable, and why:\n * - The **umbrella Space** ({@link reviewSpaceName}) and the **name prefix**\n * ({@link reviewNamePrefix}) are free text.\n * - The structural suffix `-<target-slug>-v<version>-<date>` is NOT configurable: the\n * republish flow finds the prior version by matching `\"<prefix>-<slug>-v\"` and parsing\n * the `-v<n>-` segment (see `findPriorShare` in `publish-state.ts`). Letting the suffix\n * vary would break version detection. So we expose the prefix, keep the skeleton fixed.\n *\n * Note: changing the prefix after shares already exist orphans the old-prefix versions from\n * republish detection (a fresh share starts at v1 again). That's the expected cost of\n * retargeting; the defaults reproduce the original hard-coded behaviour.\n */\nimport {_package} from '../package';\n\nexport const DEFAULT_REVIEW_SPACE = 'Proteomics-Reviews';\nexport const DEFAULT_REVIEW_NAME_PREFIX = 'Proteomics-Review';\n\n/** Reads a string package setting, falling back when unset/blank/not-yet-loaded. */\nfunction readSetting(key: string, fallback: string): string {\n try {\n const v = (_package?.settings as Record<string, unknown> | undefined)?.[key];\n if (typeof v === 'string' && v.trim().length > 0)\n return v.trim();\n } catch { /* settings not ready — use fallback */ }\n return fallback;\n}\n\n/** Umbrella Space the per-target review Spaces live under. Setting: `reviewSpaceName`. */\nexport function reviewSpaceName(): string {\n return readSetting('reviewSpaceName', DEFAULT_REVIEW_SPACE);\n}\n\n/** Prefix for the per-target child Space and the published project name.\n * Setting: `reviewNamePrefix`. The `-<slug>-v<version>-<date>` suffix stays fixed. */\nexport function reviewNamePrefix(): string {\n return readSetting('reviewNamePrefix', DEFAULT_REVIEW_NAME_PREFIX);\n}\n\n/**\n * Whether to re-open each published dashboard and assert it survives a reload\n * (the heavy round-trip check). Default ON — keep it for client deliverables;\n * turn it off via the `verifyPublishedDashboard` package setting for faster demo\n * shares. The reviewer-access verify-and-rollback gate is separate and always runs.\n */\nexport function verifyPublishedDashboard(): boolean {\n try {\n const v = (_package?.settings as Record<string, unknown> | undefined)?.['verifyPublishedDashboard'];\n if (v === false || v === 'false') return false;\n if (v === true || v === 'true') return true;\n } catch { /* settings not ready — use default */ }\n return true;\n}\n","import * as grok from 'datagrok-api/grok';\nimport * as DG from 'datagrok-api/dg';\n\nimport {reviewNamePrefix} from './publish-settings';\n\n/**\n * Single source of truth for Phase 15's published-tag namespace + pure helpers.\n *\n * Sibling pattern of `src/analysis/experiment-setup.ts`'s `getGroups`/`setGroups`:\n * tag I/O lives in one module, every consumer imports from it, no other file\n * inlines `proteomics.published*` tag string literals. A single typo in a tag\n * string would silently break the reviewer panel; centralizing is the antidote.\n */\n\n/** DE-pipeline completion gate. Exported here so Plan 05 dialog precondition\n * and Plan 07 menu handler do not inline the string (I-10 fix). */\nexport const DE_COMPLETE_TAG = 'proteomics.de_complete' as const;\n\n/**\n * Canonical published-tag keyspace. Every tag uses the `proteomics.` prefix.\n * Mirrored 1:1 by {@link META_COLUMNS} below — Plan 02 writes BOTH; Plan 06\n * reads column-first / tag-second (Pitfall 3 belt-and-braces).\n */\nexport const PUBLISHED_TAGS = {\n PUBLISHED: 'proteomics.published',\n PUBLISHED_AT: 'proteomics.published_at',\n PUBLISHED_BY: 'proteomics.published_by',\n PUBLISHED_BY_EMAIL: 'proteomics.published_by_email',\n PUBLISHED_TARGET: 'proteomics.published_target',\n PUBLISHED_DE_METHOD: 'proteomics.published_de_method',\n PUBLISHED_FC_THRESHOLD: 'proteomics.published_fc_threshold',\n PUBLISHED_P_THRESHOLD: 'proteomics.published_p_threshold',\n PUBLISHED_VERSION: 'proteomics.published_version',\n PUBLISHED_ID: 'proteomics.published_id',\n PUBLISHED_INCLUDES_ENRICHMENT: 'proteomics.published_includes_enrichment',\n SUPERSEDED_BY: 'proteomics.superseded_by',\n SUPERSEDES: 'proteomics.supersedes',\n} as const;\n\n/**\n * Belt-and-braces metadata column names. One-to-one with {@link PUBLISHED_TAGS}.\n * Plan 02 writes a single-row column per entry alongside the tag; Plan 06\n * reads column FIRST, tag SECOND so a serialization path that strips tags but\n * preserves columns (or vice versa) still recovers the metadata.\n */\nexport const META_COLUMNS = {\n PUBLISHED: '_meta_published',\n PUBLISHED_AT: '_meta_published_at',\n PUBLISHED_BY: '_meta_published_by',\n PUBLISHED_BY_EMAIL: '_meta_published_by_email',\n PUBLISHED_TARGET: '_meta_published_target',\n PUBLISHED_DE_METHOD: '_meta_published_de_method',\n PUBLISHED_FC_THRESHOLD: '_meta_published_fc_threshold',\n PUBLISHED_P_THRESHOLD: '_meta_published_p_threshold',\n PUBLISHED_VERSION: '_meta_published_version',\n PUBLISHED_ID: '_meta_published_id',\n PUBLISHED_INCLUDES_ENRICHMENT: '_meta_published_includes_enrichment',\n SUPERSEDED_BY: '_meta_superseded_by',\n SUPERSEDES: '_meta_supersedes',\n} as const;\n\n/** Typed view of one published-analysis DataFrame's metadata. */\nexport interface PublishedMetadata {\n /** Raw user input — never use directly for paths/URLs (use {@link slugifyTarget}). */\n target: string;\n /** Normalized to Date when read; ISO string accepted on write. */\n publishedAt: Date;\n publishedBy: string;\n publishedByEmail: string | null;\n deMethod: 'limma' | 'deqms' | 't-test' | 'spectronaut' | string;\n fcThreshold: number;\n pThreshold: number;\n /** Monotonically increasing per (target, group); first share is version 1. */\n version: number;\n /** The published Project's id — set after `projects.save` returns. */\n publishId: string;\n includesEnrichment: boolean;\n /** Prior Project id; null on the first share. */\n supersedes: string | null;\n /** Next Project id; set retroactively on the prior version when republishing. */\n supersededBy: string | null;\n}\n\n/** Input shape consumed by `share-dialog.ts` → `publishAnalysis(df, opts)`. */\nexport interface PublishOptions {\n target: string;\n reviewerGroup: DG.Group;\n note: string;\n /** Set by {@link findPriorShare} when this is a republish; null on first share. */\n priorVersion: DG.Project | null;\n /**\n * Test-only override for the umbrella Space name.\n * Defaults to `'Proteomics-Reviews'`. Production callers never set this;\n * Plan 08 Test 5 uses it to inject a throwaway umbrella.\n */\n umbrellaName?: string;\n /**\n * Whether to run the reopen-and-verify round trip after publishing. Set by the\n * share dialog's \"Verify published dashboard\" checkbox (which defaults to the\n * `verifyPublishedDashboard` package setting). When undefined (non-dialog callers),\n * `publishAnalysis` falls back to the package setting.\n */\n verify?: boolean;\n}\n\n/** Input shape for {@link buildMailtoUrl}. Pure data — no DOM. */\nexport interface MailtoOptions {\n sharerEmail: string | null;\n sharerName: string;\n projectName: string;\n publishedDateStr: string;\n}\n\n/** Returns true iff `proteomics.published === 'true'`. Mirror of the\n * `proteomics.de_complete === 'true'` idiom in `viewers/heatmap.ts`. */\nexport function isPublished(df: DG.DataFrame): boolean {\n return df.getTag(PUBLISHED_TAGS.PUBLISHED) === 'true';\n}\n\n/**\n * Reads the published metadata from a DataFrame, column-FIRST and tag-SECOND\n * (Pitfall 3 belt-and-braces). Returns `null` when the DataFrame is not a\n * published analysis. Returns a populated object when at least the required\n * load-bearing fields (target, publishId) are recoverable; per-field corruption\n * falls back gracefully without crashing the whole read.\n */\nexport function getPublishedMetadata(df: DG.DataFrame): PublishedMetadata | null {\n if (!isPublished(df)) return null;\n\n const readString = (colKey: keyof typeof META_COLUMNS, tagKey: keyof typeof PUBLISHED_TAGS): string | null => {\n try {\n const col = df.col(META_COLUMNS[colKey]);\n if (col != null) {\n const v = col.get(0);\n if (v != null && v !== '') return String(v);\n }\n } catch { /* fall through to tag */ }\n try {\n return df.getTag(PUBLISHED_TAGS[tagKey]) ?? null;\n } catch {\n return null;\n }\n };\n\n const readDate = (): Date | null => {\n try {\n const col = df.col(META_COLUMNS.PUBLISHED_AT);\n if (col != null) {\n const v = col.get(0);\n if (v instanceof Date) return v;\n if (typeof v === 'string' && v) return new Date(v);\n if (typeof v === 'number') return new Date(v);\n }\n } catch { /* fall through */ }\n try {\n const raw = df.getTag(PUBLISHED_TAGS.PUBLISHED_AT);\n if (raw) return new Date(raw);\n } catch { /* return null */ }\n return null;\n };\n\n const readNumber = (colKey: keyof typeof META_COLUMNS, tagKey: keyof typeof PUBLISHED_TAGS): number => {\n const s = readString(colKey, tagKey);\n if (s == null) return NaN;\n const n = parseFloat(s);\n return Number.isFinite(n) ? n : NaN;\n };\n\n const readBool = (colKey: keyof typeof META_COLUMNS, tagKey: keyof typeof PUBLISHED_TAGS): boolean => {\n const s = readString(colKey, tagKey);\n return s === 'true';\n };\n\n const target = readString('PUBLISHED_TARGET', 'PUBLISHED_TARGET');\n const publishId = readString('PUBLISHED_ID', 'PUBLISHED_ID');\n if (target == null || publishId == null) return null;\n\n const publishedAt = readDate();\n const versionRaw = readString('PUBLISHED_VERSION', 'PUBLISHED_VERSION');\n const versionNum = versionRaw != null ? parseInt(versionRaw, 10) : NaN;\n\n return {\n target,\n publishedAt: publishedAt ?? new Date(NaN),\n publishedBy: readString('PUBLISHED_BY', 'PUBLISHED_BY') ?? '',\n publishedByEmail: readString('PUBLISHED_BY_EMAIL', 'PUBLISHED_BY_EMAIL'),\n deMethod: readString('PUBLISHED_DE_METHOD', 'PUBLISHED_DE_METHOD') ?? '',\n fcThreshold: readNumber('PUBLISHED_FC_THRESHOLD', 'PUBLISHED_FC_THRESHOLD'),\n pThreshold: readNumber('PUBLISHED_P_THRESHOLD', 'PUBLISHED_P_THRESHOLD'),\n version: Number.isFinite(versionNum) ? versionNum : 1,\n publishId,\n includesEnrichment: readBool('PUBLISHED_INCLUDES_ENRICHMENT', 'PUBLISHED_INCLUDES_ENRICHMENT'),\n supersedes: readString('SUPERSEDES', 'SUPERSEDES'),\n supersededBy: readString('SUPERSEDED_BY', 'SUPERSEDED_BY'),\n };\n}\n\n/**\n * Writes every {@link PUBLISHED_TAGS} entry as a string tag on the DataFrame.\n * Pitfall 3 mitigation: even though spike 15-00 showed all 14 tags survive the\n * basic save→find→open path, `df.clone()` may not carry the full tag map;\n * Plan 02 calls this AFTER cloning to guarantee a complete tag namespace.\n *\n * Null `supersedes` / `supersededBy` are intentionally NOT written so reader\n * can disambiguate \"missing\" from \"empty\". The PUBLISHED tag is always set to\n * 'true' regardless of the metadata input.\n */\nexport function setPublishedTags(df: DG.DataFrame, meta: PublishedMetadata): void {\n df.setTag(PUBLISHED_TAGS.PUBLISHED, 'true');\n df.setTag(PUBLISHED_TAGS.PUBLISHED_AT,\n meta.publishedAt instanceof Date ? meta.publishedAt.toISOString() : String(meta.publishedAt));\n df.setTag(PUBLISHED_TAGS.PUBLISHED_BY, meta.publishedBy);\n if (meta.publishedByEmail != null)\n df.setTag(PUBLISHED_TAGS.PUBLISHED_BY_EMAIL, meta.publishedByEmail);\n df.setTag(PUBLISHED_TAGS.PUBLISHED_TARGET, meta.target);\n df.setTag(PUBLISHED_TAGS.PUBLISHED_DE_METHOD, meta.deMethod);\n df.setTag(PUBLISHED_TAGS.PUBLISHED_FC_THRESHOLD, String(meta.fcThreshold));\n df.setTag(PUBLISHED_TAGS.PUBLISHED_P_THRESHOLD, String(meta.pThreshold));\n df.setTag(PUBLISHED_TAGS.PUBLISHED_VERSION, String(meta.version));\n df.setTag(PUBLISHED_TAGS.PUBLISHED_ID, meta.publishId);\n df.setTag(PUBLISHED_TAGS.PUBLISHED_INCLUDES_ENRICHMENT, meta.includesEnrichment ? 'true' : 'false');\n if (meta.supersedes != null)\n df.setTag(PUBLISHED_TAGS.SUPERSEDES, meta.supersedes);\n if (meta.supersededBy != null)\n df.setTag(PUBLISHED_TAGS.SUPERSEDED_BY, meta.supersededBy);\n}\n\n/**\n * Sanitizes a freeform target string per D-01 into a safe slug.\n *\n * Rules:\n * - Charset `[A-Za-z0-9._-]` (case PRESERVED — do NOT lowercase)\n * - Replace runs of disallowed chars with single `-`\n * - Drop leading/trailing `-` or `.`\n * - Cap at 64 chars\n * - Empty result → `'unnamed'` (never produce empty slug — would break Project.name)\n */\nexport function slugifyTarget(raw: string): string {\n if (raw == null) return 'unnamed';\n let s = String(raw)\n .replace(/[^A-Za-z0-9._-]+/g, '-')\n .replace(/-{2,}/g, '-')\n .replace(/^[-.]+|[-.]+$/g, '')\n .slice(0, 64)\n .replace(/[-.]+$/g, '');\n if (s.length === 0) s = 'unnamed';\n return s;\n}\n\n/**\n * Looks up the most recent prior published Project matching the slugified\n * target. Used by Plan 05 (`share-dialog.ts`) for republish-detection banner\n * and Plan 04 (`publish-project.ts`) for the supersede chain.\n *\n * Smart-filter `like` confirmed working by spike 15-00 (assumption A8); the\n * fallback `list()` + client-side filter path is retained as defense in depth\n * in case the platform smart-filter parser changes.\n *\n * NOT a security gate — purely informational. T-15-05 mitigation relies on\n * the platform ACL implicitly scoping `dapi.projects.filter` to projects the\n * current user can administer.\n */\nexport async function findPriorShare(target: string, _group: DG.Group | null): Promise<DG.Project | null> {\n const slug = slugifyTarget(target);\n const namePrefix = `${reviewNamePrefix()}-${slug}-v`;\n const versionRe = /-v(\\d+)-/;\n\n const pickLatest = (cands: DG.Project[]): DG.Project | null => {\n let best: DG.Project | null = null;\n let bestV = -1;\n for (const p of cands) {\n const name = (p as any)?.name ?? '';\n const m = versionRe.exec(name);\n if (!m) continue;\n const v = parseInt(m[1], 10);\n if (Number.isFinite(v) && v > bestV) {\n bestV = v;\n best = p;\n }\n }\n return best;\n };\n\n try {\n const namePattern = `${namePrefix}%`;\n const candidates = await grok.dapi.projects.filter(`name like \"${namePattern}\"`).list();\n if (Array.isArray(candidates) && candidates.length > 0)\n return pickLatest(candidates);\n } catch { /* fall through to client-side filter */ }\n\n try {\n const all = await grok.dapi.projects.list();\n const matching = (Array.isArray(all) ? all : [])\n .filter((p) => ((p as any)?.name ?? '').startsWith(namePrefix));\n if (matching.length > 0) return pickLatest(matching);\n } catch { /* return null */ }\n\n return null;\n}\n\n/**\n * Pure helper for the reviewer panel's \"Request re-run\" button (PUB-13).\n * Builds an `encodeURIComponent`-safe `mailto:` URL with the sharer's email,\n * a project-aware subject, and a body that names the project + share date.\n *\n * Co-located here rather than in `share-dialog.ts` because Plan 06 (wave 2)\n * needs it BEFORE Plan 05 (wave 4) lands — importing wave 4 from wave 2 would\n * break the wave graph. No DOM / UI / dialog dependency.\n */\nexport function buildMailtoUrl(opts: MailtoOptions): string {\n const subject = `Re-run request: ${opts.projectName}`;\n const body = `Hi ${opts.sharerName}, could you re-run with [different parameters]? ` +\n `Looking at ${opts.projectName} (shared ${opts.publishedDateStr}).`;\n const to = opts.sharerEmail ? encodeURIComponent(opts.sharerEmail) : '';\n return `mailto:${to}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;\n}\n","import * as DG from 'datagrok-api/dg';\nimport {SEMTYPE} from './proteomics-types';\n\n/** Finds a column by semantic type, falling back to column name heuristics.\n * Lowercases each hint so callers passing mixed-case strings still match. */\nexport function findColumn(df: DG.DataFrame, semType: string, nameHints: string[]): DG.Column | null {\n const bySemType = df.columns.toList().find((c) => c.semType === semType);\n if (bySemType)\n return bySemType;\n\n for (const hint of nameHints) {\n const hintLower = hint.toLowerCase();\n const byName = df.columns.toList().find((c) => c.name.toLowerCase().includes(hintLower));\n if (byName)\n return byName;\n }\n return null;\n}\n\n/** Finds common proteomics columns in a dataframe. */\nexport function findProteomicsColumns(df: DG.DataFrame) {\n return {\n proteinId: findColumn(df, SEMTYPE.PROTEIN_ID, ['protein id', 'majority protein id', 'accession', 'uniprot']),\n geneName: findColumn(df, SEMTYPE.GENE_SYMBOL, ['gene name', 'gene symbol']),\n log2fc: findColumn(df, SEMTYPE.LOG2FC, ['log2fc', 'log2 fold', 'logfc']),\n pValue: findColumn(df, SEMTYPE.P_VALUE, ['p-value', 'pvalue', 'adj.p', 'fdr', 'q-value']),\n };\n}\n","import * as DG from 'datagrok-api/dg';\nimport * as grok from 'datagrok-api/grok';\nimport {findColumn} from './column-detection';\nimport {SEMTYPE} from './proteomics-types';\nimport {runWithConcurrency} from '../analysis/subcellular-location';\n\n// ---------------------------------------------------------------------------\n// LOCKED CLIENT CONTRACT — verbatim port of CKomics_tool2.py\n// • improve_gene_labels_with_ensrnog_marking (lines 895-1059)\n// • extract_readable_description (lines 1062-1104)\n// • get_ensembl_annotations request shape (lines 756-855)\n// D-08: inline `*` (grouped) / `†` (predicted/reclassified) markers; raw ID\n// kept in `Source ID` column.\n// D-09: Ensembl REST POST /lookup/id batched ≤1000 IDs per request, cached\n// cross-session via grok.dapi.userDataStorage with `__schema_v` invalidation.\n// D-10: duplicate gene names disambiguated with `(Source ID)` suffix; one\n// grok.shell.warning emitted per import with affected-row count.\n// ---------------------------------------------------------------------------\n\n/** userDataStorage key for the cross-session id → EnsemblEntry cache.\n * Exported so callers (and tests) can peek the cache directly. */\nexport const STORE_GENE_LABELS = 'proteomics-gene-labels';\n\n/** Bump only if the locked CK-omics resolver contract changes. Mismatch in\n * userDataStorage → stale cache discarded. */\nexport const SCHEMA_V_GENE_LABELS = '14-r1-1';\nconst SCHEMA_KEY = '__schema_v';\n\n/** Ensembl rest.ensembl.org /lookup/id hard cap (Pitfall 3). */\nconst ENS_CHUNK = 1000;\n\n/** Matches the Phase 13 UniProt cap. Ensembl rate budget is 55k req/hour\n * (≈15 req/s); FETCH_CONCURRENCY = 6 keeps us well under that bound. */\nconst FETCH_CONCURRENCY = 6;\n\n/** Predicted-pattern prefix list (CK-omics line 898-909, in this exact order). */\nexport const PREDICTED_PREFIXES = [\n 'ENSRNOG', 'ENSMUSG', 'LOC', 'ENSG', 'ENSDARG',\n 'ENSRNO', 'MGP_', 'RGD', 'AABR',\n] as const;\n\n/** Ensembl-eligible test per CK-omics line 933: only IDs starting with 'ENS'\n * OR 'MGP_' are sent to /lookup/id. LOC / RGD / AABR are NCBI / RGD /\n * Affymetrix respectively — they keep the raw ID + `†` marker only. */\nexport function isEnsemblEligible(id: string): boolean {\n return id.startsWith('ENS') || id.startsWith('MGP_');\n}\n\n/** True iff `id` starts with any locked predicted-pattern prefix. */\nexport function isPredicted(id: string): boolean {\n for (const p of PREDICTED_PREFIXES)\n if (id.startsWith(p)) return true;\n return false;\n}\n\nexport type SpeciesCode =\n 'homo_sapiens' | 'mus_musculus' | 'rattus_norvegicus' | 'danio_rerio';\n\n/** Prefix → Ensembl species code. ENSRNO falls back to rattus_norvegicus.\n * Non-Ensembl-eligible prefixes (LOC / RGD / AABR) return null so callers\n * skip them at the POST stage. */\nexport function detectSpecies(id: string): SpeciesCode | null {\n if (id.startsWith('ENSG')) return 'homo_sapiens';\n if (id.startsWith('ENSMUSG')) return 'mus_musculus';\n if (id.startsWith('MGP_')) return 'mus_musculus';\n if (id.startsWith('ENSRNOG')) return 'rattus_norvegicus';\n if (id.startsWith('ENSRNO')) return 'rattus_norvegicus';\n if (id.startsWith('ENSDARG')) return 'danio_rerio';\n return null;\n}\n\nexport interface EnsemblEntry {\n display_name?: string;\n external_name?: string;\n description?: string;\n species?: string;\n biotype?: string;\n object_type?: string;\n}\n\n/** Verbatim port of CKomics extract_readable_description (lines 1062-1104).\n * Returns null when the cleaned description is empty, still says\n * \"uncharacterized\", or is too short to be useful. */\nexport function extractReadableDescription(description: string | null | undefined): string | null {\n if (description == null || description === '') return null;\n let s = String(description);\n\n // Strip [organism] suffix.\n s = s.split('[')[0].trim();\n\n // Strip the various \"Predicted to ...\" preambles, case-insensitive, in\n // order — `enable` / `be involved in` / `be located in` / `be part of` /\n // `be` first because the bare `Predicted to ` would otherwise consume them.\n s = s.replace(/^Predicted to enable\\s+/i, '');\n s = s.replace(/^Predicted to be involved in\\s+/i, '');\n s = s.replace(/^Predicted to be located in\\s+/i, '');\n s = s.replace(/^Predicted to be part of\\s+/i, '');\n s = s.replace(/^Predicted to be\\s+/i, '');\n s = s.replace(/^Predicted to\\s+/i, '');\n\n // First sentence only.\n const sentences = s.split('.');\n if (sentences.length > 0) s = sentences[0].trim();\n\n // Strip species suffixes.\n s = s.replace(/_RAT$/i, '');\n s = s.replace(/_MOUSE$/i, '');\n s = s.replace(/_HUMAN$/i, '');\n\n // Capitalize first letter if lowercase.\n if (s.length > 0 && s[0] === s[0].toLowerCase() && s[0] !== s[0].toUpperCase())\n s = s[0].toUpperCase() + s.slice(1);\n\n // Truncate runaway descriptions (CK-omics line 1097-1098).\n if (s.length > 60) s = s.slice(0, 57) + '...';\n\n if (s === '' || s.length < 3) return null;\n if (s.toLowerCase().includes('uncharacterized')) return null;\n\n return s;\n}\n\n/** CK-omics line 1011 — `improved_name + '*'? + '†'?`. The dagger is appended\n * UNCONDITIONALLY when the resolver acted on a predicted row (CK-omics\n * `final_label = improved_name + ('*' if has_asterisk else '') + '†'`). */\nexport function applyMarkerRules(improvedName: string,\n hadAsterisk: boolean, wasReclassified: boolean): string {\n return improvedName + (hadAsterisk ? '*' : '') + (wasReclassified ? '†' : '');\n}\n\nfunction chunk<T>(arr: T[], size: number): T[][] {\n const out: T[][] = [];\n for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));\n return out;\n}\n\nasync function loadCache(): Promise<Record<string, EnsemblEntry | string>> {\n try {\n const raw = (await grok.dapi.userDataStorage.get(STORE_GENE_LABELS)) ?? {};\n if ((raw as any)[SCHEMA_KEY] !== SCHEMA_V_GENE_LABELS)\n return {[SCHEMA_KEY]: SCHEMA_V_GENE_LABELS};\n return raw as Record<string, EnsemblEntry | string>;\n } catch {\n return {[SCHEMA_KEY]: SCHEMA_V_GENE_LABELS};\n }\n}\n\nasync function flushCache(cache: Record<string, EnsemblEntry | string>,\n fetched: Record<string, EnsemblEntry>): Promise<void> {\n try {\n await grok.dapi.userDataStorage.put(STORE_GENE_LABELS,\n {...cache, ...fetched, [SCHEMA_KEY]: SCHEMA_V_GENE_LABELS});\n } catch (e: any) {\n console.warn(`Gene-label cache write failed: ${e?.message ?? e}`);\n }\n}\n\n/** One POST to https://rest.ensembl.org/lookup/id with body `{ids: [...]}`.\n * Honours a single 429 retry-after backoff per chunk. Warn-and-continue on\n * any other error; the resolver must not block import on Ensembl flakes. */\nexport async function lookupEnsemblBatch(ids: string[]): Promise<Map<string, EnsemblEntry>> {\n const out = new Map<string, EnsemblEntry>();\n if (ids.length === 0) return out;\n\n const post = async (): Promise<Response> => grok.dapi.fetchProxy(\n 'https://rest.ensembl.org/lookup/id',\n {\n method: 'POST',\n headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},\n body: JSON.stringify({ids}),\n },\n );\n\n let resp: Response;\n try {\n resp = await post();\n } catch (e: any) {\n console.warn(`Ensembl lookup/id batch failed (network): ${e?.message ?? e}`);\n return out;\n }\n\n if (resp.status === 429) {\n // Single retry per CK-omics line 822-825 contract; Retry-After header in\n // seconds (fractional allowed). Cap the back-off at 30s to keep import\n // responsive — the resolver degrades gracefully on continued failure.\n const retryAfter = parseFloat(resp.headers.get('Retry-After') ?? '1');\n const waitMs = Math.min(30_000, Math.max(0, retryAfter * 1000));\n await new Promise((res) => setTimeout(res, waitMs));\n try {\n resp = await post();\n } catch (e: any) {\n console.warn(`Ensembl lookup/id retry failed: ${e?.message ?? e}`);\n return out;\n }\n }\n\n if (!resp.ok) {\n console.warn(`Ensembl lookup/id returned status ${resp.status}; continuing`);\n return out;\n }\n\n let body: any;\n try {\n body = await resp.json();\n } catch (e: any) {\n console.warn(`Ensembl lookup/id JSON parse failed: ${e?.message ?? e}`);\n return out;\n }\n\n if (body && typeof body === 'object') {\n for (const [id, entry] of Object.entries(body)) {\n if (entry && typeof entry === 'object') {\n const e = entry as Record<string, unknown>;\n // Type-guard every field read (threat T-14-01-T1).\n const safe: EnsemblEntry = {};\n if (typeof e.display_name === 'string') safe.display_name = e.display_name;\n if (typeof e.external_name === 'string') safe.external_name = e.external_name;\n if (typeof e.description === 'string') safe.description = e.description;\n if (typeof e.species === 'string') safe.species = e.species;\n if (typeof e.biotype === 'string') safe.biotype = e.biotype;\n if (typeof e.object_type === 'string') safe.object_type = e.object_type;\n out.set(id, safe);\n }\n }\n }\n return out;\n}\n\n/** Three-level fallback per CK-omics lines 800-804:\n * external_name → display_name → description.split('[')[0].strip() → raw ID.\n * Acceptance gate per CK-omics lines 977-988: reject the candidate if it equals\n * the raw ID OR starts with a predicted prefix. */\nfunction pickBestName(rawId: string, entry: EnsemblEntry | undefined): string | null {\n if (!entry) return null;\n const candidates: Array<string | undefined> = [\n entry.external_name,\n entry.display_name,\n entry.description ? entry.description.split('[')[0].trim() : undefined,\n ];\n for (const c of candidates) {\n if (c && c !== rawId && !isPredicted(c)) return c;\n }\n return null;\n}\n\nexport type GeneLabelProgress = (done: number, total: number,\n phase: 'lookup' | 'apply') => void;\n\n/** Public entry — runs after every parser produces its DataFrame. Always\n * creates `Display Name` and `Source ID` columns even when no predicted IDs\n * are present (Pitfall 9: downstream Volcano label bindings depend on the\n * `Display Name` invariant). The resolver degrades gracefully on Ensembl\n * outages — analyst sees raw IDs + a single warning toast.\n */\nexport async function resolveGeneLabels(df: DG.DataFrame,\n progress?: GeneLabelProgress): Promise<void> {\n const geneCol = findColumn(df, SEMTYPE.GENE_SYMBOL, ['gene name', 'gene names', 'gene symbol']);\n const n = df.rowCount;\n const displayArr: string[] = new Array(n).fill('');\n const sourceArr: string[] = new Array(n).fill('');\n\n // Pre-fill from Gene name (when present); the resolver overrides specific\n // rows below. Rows without a Gene name source still get '' for both, so the\n // columns are always rectangular.\n if (geneCol != null) {\n for (let i = 0; i < n; i++) {\n const raw = geneCol.get(i);\n const s = (raw == null) ? '' : String(raw);\n displayArr[i] = s;\n }\n }\n\n // Identify rows whose Gene name (stripped of pre-existing * and †) matches a\n // predicted-pattern prefix. CK-omics line 916-925: also walks FirstGene /\n // FirstUniProt columns. Datagrok's parsers normalize to a single Gene name\n // column, so checking that column is sufficient — but if the proteomics\n // primary protein id column happens to also be a predicted Ensembl ID, we\n // honour the same logic on it.\n const idCol = findColumn(df, SEMTYPE.PROTEIN_ID,\n ['protein ids', 'primary protein id', 'protein id', 'majority protein ids', 'accession', 'uniprot']);\n\n /** Per-row work item carrying the raw ID we want to resolve. */\n type Predicted = {row: number; clean: string; hadAsterisk: boolean; source: 'gene' | 'protein'};\n const predicted: Predicted[] = [];\n\n const recordIfPredicted = (row: number, raw: string, source: 'gene' | 'protein'): boolean => {\n if (!raw) return false;\n const hadAsterisk = raw.includes('*');\n const clean = raw.replace(/[*†]/g, '');\n if (!isPredicted(clean)) return false;\n predicted.push({row, clean, hadAsterisk, source});\n return true;\n };\n\n for (let i = 0; i < n; i++) {\n const g = geneCol != null ? geneCol.get(i) : null;\n const gs = g == null ? '' : String(g);\n if (recordIfPredicted(i, gs, 'gene')) continue;\n // Fall through to protein id only when gene name isn't a predicted ID.\n if (idCol != null) {\n const p = idCol.get(i);\n const ps = p == null ? '' : String(p).split(';')[0];\n recordIfPredicted(i, ps, 'protein');\n }\n }\n\n // Always ensure the two new columns exist (Pitfall 9). Remove first if a\n // re-run is in progress so we re-init cleanly.\n for (const name of ['Display Name', 'Source ID']) {\n const existing = df.col(name);\n if (existing != null) df.columns.remove(name);\n }\n // Fast path: no predicted IDs → write columns and exit, but always create\n // them. Display Name = raw gene name (or ''), Source ID = ''.\n if (predicted.length === 0) {\n const dCol = df.columns.addNewString('Display Name');\n dCol.init((i) => displayArr[i]);\n dCol.semType = SEMTYPE.DISPLAY_NAME;\n const sCol = df.columns.addNewString('Source ID');\n sCol.init((i) => sourceArr[i]);\n sCol.semType = SEMTYPE.SOURCE_ID;\n return;\n }\n\n // Collect unique predicted IDs and the Ensembl-eligible subset.\n const uniqueIds = [...new Set(predicted.map((p) => p.clean))];\n const ensIds = uniqueIds.filter((id) => isEnsemblEligible(id));\n\n const cache = await loadCache();\n const fetched: Record<string, EnsemblEntry> = {};\n const lookupResult = new Map<string, EnsemblEntry>();\n\n // Seed from cache.\n for (const id of ensIds) {\n const c = cache[id];\n if (c && typeof c === 'object') lookupResult.set(id, c as EnsemblEntry);\n }\n const misses = ensIds.filter((id) => !lookupResult.has(id));\n\n let unresolvedAny = false;\n if (misses.length > 0) {\n const chunks = chunk(misses, ENS_CHUNK);\n const total = chunks.length;\n let done = 0;\n try {\n await runWithConcurrency(chunks, FETCH_CONCURRENCY, async (group) => {\n const got = await lookupEnsemblBatch(group);\n for (const [id, entry] of got) {\n lookupResult.set(id, entry);\n fetched[id] = entry;\n }\n // Anything in `group` that didn't come back is unresolved by Ensembl —\n // we still mark the row reclassified, but Display Name falls back to\n // the raw ID. Track this so the warning toast can name it.\n for (const id of group) if (!got.has(id)) unresolvedAny = true;\n done++;\n progress?.(done, total, 'lookup');\n });\n } finally {\n await flushCache(cache, fetched);\n }\n }\n\n // Apply the marker / fallback rules per predicted row.\n // CK-omics fallback chain when Ensembl yielded nothing: try the\n // ProteinDescriptions column (CK-omics line 997-1005). Datagrok parsers\n // surface this as \"Protein Descriptions\" (Spectronaut) or \"Protein names\"\n // (MaxQuant); we accept either by name.\n const descCol = df.col('Protein Descriptions') ?? df.col('Protein names')\n ?? df.col('Description') ?? df.col('protein_descriptions');\n\n let reclassified = 0;\n for (const p of predicted) {\n const entry = lookupResult.get(p.clean);\n let improved: string | null = pickBestName(p.clean, entry);\n\n if (improved == null && entry != null) {\n const cleaned = extractReadableDescription(entry.description ?? null);\n if (cleaned != null && cleaned !== p.clean && !isPredicted(cleaned))\n improved = cleaned;\n }\n\n // ProteinDescriptions fallback.\n if (improved == null && descCol != null) {\n const dRaw = descCol.get(p.row);\n const cleaned = extractReadableDescription(dRaw == null ? null : String(dRaw));\n if (cleaned != null && cleaned !== p.clean && !isPredicted(cleaned) && cleaned.length > 3)\n improved = cleaned;\n }\n\n // If still nothing, keep raw ID — marker still appended (CK-omics line 1011).\n const finalName = applyMarkerRules(improved ?? p.clean, p.hadAsterisk, true);\n displayArr[p.row] = finalName;\n sourceArr[p.row] = p.clean;\n reclassified++;\n }\n progress?.(predicted.length, predicted.length, 'apply');\n\n // D-10 duplicate disambiguation. Group rows by Display Name; if a name maps\n // to >1 distinct Source ID, append `(Source ID)` to each of those rows.\n const byName = new Map<string, Set<string>>();\n const rowsByName = new Map<string, number[]>();\n for (let i = 0; i < n; i++) {\n const name = displayArr[i];\n const src = sourceArr[i];\n if (!name || !src) continue;\n if (!byName.has(name)) byName.set(name, new Set());\n byName.get(name)!.add(src);\n if (!rowsByName.has(name)) rowsByName.set(name, []);\n rowsByName.get(name)!.push(i);\n }\n let duplicateRows = 0;\n for (const [name, srcs] of byName) {\n if (srcs.size <= 1) continue;\n for (const r of rowsByName.get(name) ?? []) {\n const sid = sourceArr[r];\n if (!sid) continue;\n displayArr[r] = `${name} (${sid})`;\n duplicateRows++;\n }\n }\n if (duplicateRows > 0) {\n grok.shell.warning(`${duplicateRows} duplicate gene names disambiguated with source IDs.`);\n }\n\n if (unresolvedAny) {\n const unresolvedCount = predicted.filter((p) =>\n isEnsemblEligible(p.clean) && !lookupResult.has(p.clean)).length;\n grok.shell.warning(\n `Ensembl gene-label resolution unavailable. Showing raw IDs (${unresolvedCount} unresolved). Re-import to retry.`,\n );\n }\n\n const dCol = df.columns.addNewString('Display Name');\n dCol.init((i) => displayArr[i]);\n dCol.semType = SEMTYPE.DISPLAY_NAME;\n const sCol = df.columns.addNewString('Source ID');\n sCol.init((i) => sourceArr[i]);\n sCol.semType = SEMTYPE.SOURCE_ID;\n\n // Silence unused-warning for `reclassified` — kept for future telemetry.\n void reclassified;\n}\n","import * as DG from 'datagrok-api/dg';\n\n/**\n * Single source of truth for the organisms the package supports for g:Profiler\n * enrichment and UniProt subcellular-location narrowing. `code` is the g:Profiler\n * organism id; `display` is the user-facing dropdown label. Moved here (a leaf\n * module) from `analysis/enrichment.ts` so parsers, the annotate dialog, and\n * enrichment can all share it without a circular import.\n */\nexport const ORGANISM_LIST = [\n {display: 'Homo sapiens (Human)', code: 'hsapiens'},\n {display: 'Mus musculus (Mouse)', code: 'mmusculus'},\n {display: 'Rattus norvegicus (Rat)', code: 'rnorvegicus'},\n {display: 'Saccharomyces cerevisiae (Yeast)', code: 'scerevisiae'},\n {display: 'Escherichia coli (K12)', code: 'ecoli'},\n {display: 'Danio rerio (Zebrafish)', code: 'drerio'},\n {display: 'Drosophila melanogaster (Fruit fly)', code: 'dmelanogaster'},\n {display: 'Arabidopsis thaliana', code: 'athaliana'},\n {display: 'Caenorhabditis elegans', code: 'celegans'},\n] as const;\n\n/** Scientific-name prefix (lowercased, parenthetical stripped) → g:Profiler code,\n * derived once from ORGANISM_LIST. e.g. 'homo sapiens' → 'hsapiens'. */\nconst SCIENTIFIC_TO_CODE: ReadonlyArray<{scientific: string; code: string}> =\n ORGANISM_LIST.map((o) => ({\n scientific: o.display.split('(')[0].trim().toLowerCase(),\n code: o.code,\n }));\n\n/** Display label → code and code → display, for dialog seeding. */\nexport function organismDisplayForCode(code: string | undefined): string | undefined {\n return ORGANISM_LIST.find((o) => o.code === code)?.display;\n}\nexport function organismCodeForDisplay(display: string | undefined): string | undefined {\n return ORGANISM_LIST.find((o) => o.display === display)?.code;\n}\n\n/**\n * Maps a raw UniProt/Spectronaut organism-name string to a g:Profiler code, or\n * undefined if it matches none of the supported organisms. Matches on the\n * scientific-name prefix so strain-qualified values resolve too — e.g.\n * \"Escherichia coli (strain K12)\" → 'ecoli', \"Rattus norvegicus\" → 'rnorvegicus'.\n */\nexport function resolveOrganismCode(name: string | null | undefined): string | undefined {\n if (!name) return undefined;\n const lower = name.toLowerCase();\n for (const {scientific, code} of SCIENTIFIC_TO_CODE)\n if (lower.includes(scientific)) return code;\n return undefined;\n}\n\n/** Column-name hints for the per-protein organism column that some vendors emit\n * (Spectronaut's `PG.Organisms`; generic \"Organism\"/\"Species\"). */\nconst ORGANISM_COLUMN_HINTS = ['pg.organisms', 'organism', 'organisms', 'species'];\n\nfunction findOrganismColumn(df: DG.DataFrame): DG.Column | null {\n for (const col of df.columns.toList()) {\n const n = col.name.toLowerCase();\n if (ORGANISM_COLUMN_HINTS.some((h) => n === h || n.includes(h))) return col;\n }\n return null;\n}\n\n/**\n * Infers the experiment's organism from an organism column in the data, when the\n * data is unambiguously a single supported species. Returns the g:Profiler code,\n * or undefined when there is no organism column, nothing resolves, or MORE THAN\n * ONE supported organism is present (e.g. a HYE multi-species mix) — in which\n * case the caller should leave the choice to the user rather than guess.\n */\nexport function detectOrganismCode(df: DG.DataFrame): string | undefined {\n const col = findOrganismColumn(df);\n if (!col) return undefined;\n const codes = new Set<string>();\n for (let i = 0; i < col.length; i++) {\n if (col.isNone(i)) continue;\n const code = resolveOrganismCode(col.get(i) as string);\n if (code) codes.add(code);\n if (codes.size > 1) return undefined; // ambiguous — don't guess\n }\n return codes.size === 1 ? [...codes][0] : undefined;\n}\n","export const SEMTYPE = {\n PROTEIN_ID: 'Proteomics-ProteinId',\n GENE_SYMBOL: 'Proteomics-GeneSymbol',\n LOG2FC: 'Proteomics-Log2FC',\n P_VALUE: 'Proteomics-PValue',\n INTENSITY: 'Proteomics-Intensity',\n SUBCELLULAR_LOCATION: 'Proteomics-SubcellularLocation',\n DISPLAY_NAME: 'Proteomics-DisplayName',\n SOURCE_ID: 'Proteomics-SourceId',\n NUMERATOR_MEAN: 'Proteomics-NumeratorMean',\n DENOMINATOR_MEAN: 'Proteomics-DenominatorMean',\n} as const;\n\n/** Default significance cutoffs — the SINGLE source for the |log2FC| ≥ 1 and\n * adj.p ≤ 0.05 thresholds used as dialog defaults, function-parameter defaults,\n * and `?? ` fallbacks across DE, enrichment, the volcano, and the demos. Never\n * re-inline the literals; import these so the pipeline stays internally\n * consistent when a default is retuned. */\nexport const DEFAULT_FC_THRESHOLD = 1.0;\nexport const DEFAULT_P_THRESHOLD = 0.05;\n\n/** Locked direction palette (D-04): numerator/group1 = magenta, denominator/\n * group2 = cyan, not-significant = gray, as ARGB ints. Single source shared by\n * the volcano direction column and the UniProt panel's per-group bar chart —\n * lives here (a leaf module) so both can import without a circular dependency. */\nexport const DIRECTION_COLORS_BASE = {\n enrichedG1: 0xFFFF00FF, // magenta (ARGB)\n enrichedG2: 0xFF00FFFF, // cyan (ARGB)\n notSig: 0xFFAAAAAA, // gray (ARGB)\n} as const;\n","import * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\nimport * as rxjs from 'rxjs';\nimport {findColumn} from '../utils/column-detection';\nimport {SEMTYPE} from '../utils/proteomics-types';\n\n/** Module-level subscriptions for cleanup on re-open. */\nlet activeSubscriptions: rxjs.Subscription[] = [];\n\n/** Default number of terms each dot/bar chart shows (per direction). */\nexport const CHART_TOP_N = 15;\n\n/** Value/color column the dot + bar charts read. Kept as a plain (non-`~`)\n * name because it is a viewer VALUE binding — a missing value column hard-fails\n * a bar chart on reopen (the original \"Column negLog10FDR does not exist\" bug). */\nexport const NEG_LOG10_FDR_COL = 'negLog10FDR';\n/** Hidden marker column (auto-hidden via `~` prefix, ignored by the publish\n * shape contract) flagging the top-N terms per direction. Used only inside the\n * per-viewer formula filter, where a parse failure degrades to \"show all\"\n * rather than crashing — so the `~` name is safe here but not for the value. */\nexport const CHART_TOP_MARKER_COL = '~enrichChartTop';\n\n/**\n * Adds the two derived columns the enrichment dot/bar charts bind to, directly\n * onto `enrichDf` (idempotent — ensureFreshFloat pattern):\n * - `negLog10FDR` — -log10(FDR); dot color + bar value. FDR=0 (underflow /\n * extreme enrichment) maps to the float-underflow ceiling so it stays\n * visible without colliding with real values like FDR=1e-10.\n * - `~enrichChartTop` — true for the top-N terms by FDR (ascending) within\n * each Direction, or overall when there is no Direction column.\n *\n * Both charts bind to `enrichDf` itself rather than to cloned subsets: docked\n * viewers rebind to their host view's primary frame on project reopen, so the\n * columns they read must live on that frame (else the bar chart fatal-errors).\n * Keeping everything on one frame also stops the subset tables from leaking\n * into a published project's table tree.\n */\nexport function prepareEnrichmentChartColumns(enrichDf: DG.DataFrame, topN: number = CHART_TOP_N): void {\n const fdrCol = enrichDf.col('FDR');\n if (!fdrCol) return;\n\n const UNDERFLOW_NEGLOG10 = -Math.log10(Number.MIN_VALUE);\n const fdrRaw = fdrCol.getRawData() as Float32Array | Float64Array;\n if (enrichDf.columns.contains(NEG_LOG10_FDR_COL)) enrichDf.columns.remove(NEG_LOG10_FDR_COL);\n const negLogCol = enrichDf.columns.addNewFloat(NEG_LOG10_FDR_COL);\n negLogCol.init((i) => fdrRaw[i] > 0 ? -Math.log10(fdrRaw[i]) : UNDERFLOW_NEGLOG10);\n // Keep it out of the reviewer's grid (best-effort; `~` isn't usable on a\n // viewer value binding). If the tag is stripped on round-trip the only cost\n // is one extra, meaningful numeric column in the grid.\n negLogCol.setTag('.hidden', 'true');\n\n // Rank terms by FDR (ascending) within each direction and mark the top N.\n const dirCol = enrichDf.col('Direction');\n const groups = new Map<string, {idx: number; fdr: number}[]>();\n for (let i = 0; i < enrichDf.rowCount; i++) {\n if (fdrCol.isNone(i)) continue;\n const key = dirCol ? String(dirCol.get(i)) : '';\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push({idx: i, fdr: fdrCol.get(i) as number});\n }\n const topMask = new Array<boolean>(enrichDf.rowCount).fill(false);\n for (const arr of groups.values()) {\n arr.sort((a, b) => a.fdr - b.fdr);\n for (let k = 0; k < Math.min(topN, arr.length); k++)\n topMask[arr[k].idx] = true;\n }\n if (enrichDf.columns.contains(CHART_TOP_MARKER_COL)) enrichDf.columns.remove(CHART_TOP_MARKER_COL);\n enrichDf.columns.addNewBool(CHART_TOP_MARKER_COL).init((i) => topMask[i]);\n}\n\n/** Per-viewer formula filter: the top-N marked terms, optionally narrowed to one\n * regulation direction. Degrades to \"show all rows\" if the platform drops the\n * formula on reopen — never a missing-column crash. */\nfunction chartFilter(direction?: 'Up' | 'Down'): string {\n const clauses = [`\\${${CHART_TOP_MARKER_COL}}`];\n if (direction) clauses.push(`\\${Direction} == \"${direction}\"`);\n return clauses.join(' and ');\n}\n\n/**\n * Creates an enrichment dot plot bound to the shared enrichment frame.\n * X = Gene Ratio, Y = Term Name, size = Gene Count, color = -log10(FDR).\n * Pass `direction` to split into Up/Down via a per-viewer formula filter.\n */\nexport function createEnrichmentDotPlot(enrichDf: DG.DataFrame, direction?: 'Up' | 'Down'): DG.ScatterPlotViewer {\n const sp = DG.Viewer.scatterPlot(enrichDf, {\n x: 'Gene Ratio',\n y: 'Term Name',\n sizeColumnName: 'Gene Count',\n colorColumnName: NEG_LOG10_FDR_COL,\n markerMinSize: 5,\n markerMaxSize: 25,\n filter: chartFilter(direction),\n title: direction ? `Enrichment — ${direction}` : 'Enrichment Dot Plot',\n } as any);\n return sp;\n}\n\n/**\n * Creates an enrichment bar chart (top terms ranked by -log10(FDR)) bound to the\n * shared enrichment frame. Pass `direction` to split into Up/Down.\n */\nexport function createEnrichmentBarChart(enrichDf: DG.DataFrame, direction?: 'Up' | 'Down'): DG.Viewer {\n const bar = DG.Viewer.barChart(enrichDf, {\n splitColumnName: 'Term Name',\n valueColumnName: NEG_LOG10_FDR_COL,\n valueAggrType: 'avg',\n barSortType: 'by value',\n barSortOrder: 'desc',\n orientation: 'Horizontal',\n filter: chartFilter(direction),\n title: direction ? `Top Enriched — ${direction}` : 'Top Enriched Terms',\n } as any);\n return bar;\n}\n\n/**\n * Wires enrichment row changes to protein DataFrame selection.\n * When a row is selected in the enrichment table, matching protein rows\n * (by gene symbol from the Intersection column) are highlighted.\n */\nexport function wireEnrichmentToVolcano(\n enrichDf: DG.DataFrame,\n proteinDf: DG.DataFrame,\n): rxjs.Subscription {\n const geneCol = findColumn(proteinDf, SEMTYPE.GENE_SYMBOL, ['gene name', 'gene symbol']);\n if (!geneCol) return rxjs.Subscription.EMPTY;\n\n // Build gene-to-row index\n const geneToRows = new Map<string, number[]>();\n for (let i = 0; i < proteinDf.rowCount; i++) {\n if (!geneCol.isNone(i)) {\n const gene = (geneCol.get(i) as string).trim();\n if (!geneToRows.has(gene)) geneToRows.set(gene, []);\n geneToRows.get(gene)!.push(i);\n }\n }\n\n return enrichDf.onCurrentRowChanged.subscribe(() => {\n const rowIdx = enrichDf.currentRowIdx;\n if (rowIdx < 0) return;\n\n const intersectionCol = enrichDf.col('Intersection');\n if (!intersectionCol) return;\n\n const memberGenesStr = intersectionCol.get(rowIdx) as string;\n if (!memberGenesStr) return;\n\n const memberGenes = memberGenesStr.split(',').map((g) => g.trim()).filter(Boolean);\n\n // Clear previous selection\n proteinDf.selection.setAll(false, false);\n\n // Set selection for matching genes\n for (const gene of memberGenes) {\n const rows = geneToRows.get(gene);\n if (rows) {\n for (const row of rows)\n proteinDf.selection.set(row, true, false);\n }\n }\n proteinDf.selection.fireChanged();\n });\n}\n\n/** True when `enrichDf` carries a Direction column with at least one row in\n * `direction`. Drives the Up/Down 2×2 vs single-chart layout choice. */\nfunction hasDirection(enrichDf: DG.DataFrame, direction: 'Up' | 'Down'): boolean {\n const dirCol = enrichDf.col('Direction');\n if (!dirCol) return false;\n for (let i = 0; i < enrichDf.rowCount; i++) {\n if (dirCol.get(i) === direction) return true;\n }\n return false;\n}\n\n/**\n * Opens a full enrichment visualization dashboard with dot plot, bar chart,\n * and cross-DataFrame selection wiring to the protein table. When the result\n * carries an R2 Direction column with both Up and Down rows, the Up and Down\n * dot+bar charts are docked side-by-side; otherwise the original single\n * dot+bar layout is used. The Phase-9 volcano cross-link is unchanged.\n */\nexport function openEnrichmentVisualization(\n enrichDf: DG.DataFrame,\n proteinDf: DG.DataFrame,\n): DG.TableView {\n // Clean up previous subscriptions\n for (const sub of activeSubscriptions)\n sub.unsubscribe();\n activeSubscriptions = [];\n\n // Find or reuse the enrichment results table view. Match by stable .dart\n // identity, NOT `=== enrichDf`: grok.shell.tableViews returns a fresh toJs\n // wrapper per access, so strict-equality misses an already-open view and\n // spawns a duplicate \"Enrichment Results (2)\" tab (precedent: the protein-TV\n // lookup that used to live here; 13-07 SUMMARY).\n let existing: DG.TableView | undefined;\n for (const v of grok.shell.tableViews) {\n if ((v.dataFrame as any)?.dart === (enrichDf as any).dart) { existing = v; break; }\n }\n const tv = existing ?? grok.shell.addTableView(enrichDf);\n\n // Dock the dot/bar charts onto the ENRICHMENT results view — not the protein\n // view where the volcano lives — so the volcano tab stays uncluttered\n // (light-touch declutter). Surface this view FIRST: docking onto a\n // backgrounded host leaves zero-dimension dock splitters and crashes the Dart\n // scatter plot's smart-labels with\n // \"Failed to execute 'drawImage'... canvas with width or height of 0\".\n grok.shell.v = tv;\n const chartHost = tv;\n\n // D-14 — surface the smart-filter transform stats above the grid when it\n // actually dropped rows. Tag is set only by runEnrichmentPipeline when\n // kept < total; the banner copy is locked in 14-UI-SPEC.md §\"Copywriting\".\n if (enrichDf.getTag('proteomics.enrichment_smart_filtered') === 'true') {\n const kept = enrichDf.getTag('proteomics.enrichment_smart_filtered_kept') ?? '?';\n const total = enrichDf.getTag('proteomics.enrichment_smart_filtered_total') ?? '?';\n const parents = enrichDf.getTag('proteomics.enrichment_smart_filtered_dropped_parents') ?? '?';\n const cap = enrichDf.getTag('proteomics.enrichment_smart_filtered_cap') ?? '15';\n const banner = ui.divText(\n `Smart pathway filter active: showing ${kept} of ${total} terms ` +\n `(dropped ${parents} generic parents, capped at ${cap} per source). ` +\n `Re-run with the filter off to see all.`);\n banner.dataset.smartFilterBanner = 'true';\n tv.dockManager.dock(banner, DG.DOCK_TYPE.TOP, null, 'Smart Filter Info', 0.1);\n }\n\n // Dock the dot/bar charts (extracted so the publish path reuses the exact\n // 2×2) and cross-link the frame. Every chart binds to `enrichDf` itself, so\n // the single full-frame wiring covers all of them (and keeps the Intersection\n // column the Phase-9 wiring keys on).\n dockEnrichmentCharts(chartHost, enrichDf);\n activeSubscriptions.push(wireEnrichmentToVolcano(enrichDf, proteinDf));\n\n // The dot/bar charts, the merged enrichment grid, and the smart-filter banner\n // all share this enrichment tab; the volcano stays on its own (protein) tab.\n // The cross-link keeps the two tabs in sync on selection.\n return tv;\n}\n\n/** Docks the directional (Up|Down 2×2) or single Dot+Bar enrichment charts onto\n * `host`. Every chart binds to `enrichDf` itself — the derived `negLog10FDR` /\n * `~enrichChartTop` columns are added to that frame and the Up/Down split is a\n * per-viewer formula filter. No cloned subsets, so nothing leaks into a\n * published project's table tree and the charts survive a project round-trip\n * (docked viewers rebind to their host frame on reopen). Pure layout — no\n * subscriptions, no focus changes — shared by the live and publish paths. */\nexport function dockEnrichmentCharts(host: DG.TableView, enrichDf: DG.DataFrame): void {\n prepareEnrichmentChartColumns(enrichDf);\n\n if (hasDirection(enrichDf, 'Up') && hasDirection(enrichDf, 'Down')) {\n // Balanced 2×2: [Up Dot | Down Dot] over [Up Bar | Down Bar]. Split the\n // chart region into the two columns FIRST, THEN drop each bar under its dot\n // — docking the bars before the split carved up only the top-left cell and\n // produced a lopsided layout.\n const upDotNode = host.dockManager.dock(\n createEnrichmentDotPlot(enrichDf, 'Up'), DG.DOCK_TYPE.RIGHT, null, 'Up — Dot Plot', 0.6);\n const downDotNode = host.dockManager.dock(\n createEnrichmentDotPlot(enrichDf, 'Down'), DG.DOCK_TYPE.RIGHT, upDotNode, 'Down — Dot Plot', 0.5);\n host.dockManager.dock(\n createEnrichmentBarChart(enrichDf, 'Up'), DG.DOCK_TYPE.DOWN, upDotNode, 'Up — Bar Chart', 0.5);\n host.dockManager.dock(\n createEnrichmentBarChart(enrichDf, 'Down'), DG.DOCK_TYPE.DOWN, downDotNode, 'Down — Bar Chart', 0.5);\n return;\n }\n\n // Single-direction or no Direction column → one Dot + Bar.\n const dotNode = host.dockManager.dock(\n createEnrichmentDotPlot(enrichDf), DG.DOCK_TYPE.RIGHT, null, 'Dot Plot', 0.5);\n host.dockManager.dock(\n createEnrichmentBarChart(enrichDf), DG.DOCK_TYPE.DOWN, dotNode, 'Bar Chart', 0.5);\n}\n","import * as DG from 'datagrok-api/dg';\nimport {findColumn} from '../utils/column-detection';\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {getGroups, GroupAssignment} from '../analysis/experiment-setup';\n\n/**\n * R4 / D-12 — Group-Mean Correlation viewer.\n *\n * Adds two derived columns to the host DataFrame (Numerator Mean, Denominator\n * Mean — means of the group1/group2 intensity columns per row) and renders\n * them as a scatter colored by the existing `direction` column (magenta/cyan/\n * gray per D-04). The viewer title carries inline Pearson r and Spearman ρ\n * over the current filter; a y=x diagonal reference line is drawn in #888888.\n *\n * The derived columns are re-run-safe via `ensureFreshFloat` — a second\n * invocation replaces the columns instead of duplicating them.\n *\n * Statistics: `@datagrok-libraries/statistics` exports only Kendall's tau,\n * so Pearson and Spearman are implemented inline (Pearson over raw values,\n * Spearman = Pearson over fractional ranks).\n */\n\nconst NUMERATOR_MEAN_COL = 'Numerator Mean';\nconst DENOMINATOR_MEAN_COL = 'Denominator Mean';\nconst DIRECTION_COL = 'direction';\nconst DIAGONAL_FORMULA = `\\${${NUMERATOR_MEAN_COL}} = \\${${DENOMINATOR_MEAN_COL}}`;\nconst DIAGONAL_COLOR = '#888888';\n\n/** Bulk-init pattern — removes an existing column first to avoid duplicates on\n * re-run. Mirrors src/viewers/qc-computations.ts:28-32. */\nfunction ensureFreshFloat(df: DG.DataFrame, name: string): DG.Column {\n if (df.columns.contains(name))\n df.columns.remove(name);\n return df.columns.addNewFloat(name);\n}\n\n/** Mean of non-null values across `cols` at `rowIdx`. Returns NaN if every\n * value is null. Mirrors qc-computations.ts:15-25. */\nfunction groupMean(cols: DG.Column[], rowIdx: number): number {\n let sum = 0;\n let n = 0;\n for (const c of cols) {\n if (c.isNone(rowIdx)) continue;\n sum += c.get(rowIdx) as number;\n n++;\n }\n return n > 0 ? sum / n : NaN;\n}\n\n/**\n * Derives Numerator Mean (group1) and Denominator Mean (group2) columns on\n * `df`. The join key is the protein row index — never a derived key like\n * gene name (project memory project_proteomics_deqms_result_misalignment).\n *\n * The columns carry the dedicated SEMTYPE.NUMERATOR_MEAN / SEMTYPE.DENOMINATOR_MEAN\n * tags so downstream tooling can find them via `findColumn`.\n */\nexport function computeGroupMeans(df: DG.DataFrame, groups: GroupAssignment): void {\n const g1Cols = groups.group1.columns\n .map((n) => df.col(n))\n .filter((c): c is DG.Column => c != null);\n const g2Cols = groups.group2.columns\n .map((n) => df.col(n))\n .filter((c): c is DG.Column => c != null);\n\n const nRows = df.rowCount;\n const numArr = new Float32Array(nRows);\n const denArr = new Float32Array(nRows);\n for (let i = 0; i < nRows; i++) {\n const m1 = groupMean(g1Cols, i);\n const m2 = groupMean(g2Cols, i);\n numArr[i] = isNaN(m1) ? DG.FLOAT_NULL : m1;\n denArr[i] = isNaN(m2) ? DG.FLOAT_NULL : m2;\n }\n\n const numCol = ensureFreshFloat(df, NUMERATOR_MEAN_COL);\n numCol.init((i) => numArr[i]);\n numCol.semType = SEMTYPE.NUMERATOR_MEAN;\n\n const denCol = ensureFreshFloat(df, DENOMINATOR_MEAN_COL);\n denCol.init((i) => denArr[i]);\n denCol.semType = SEMTYPE.DENOMINATOR_MEAN;\n}\n\n/** Pearson correlation. Skips paired entries containing NaN or FLOAT_NULL. */\nexport function pearson(xs: number[], ys: number[]): number {\n let n = 0;\n let sumX = 0;\n let sumY = 0;\n for (let i = 0; i < xs.length; i++) {\n const x = xs[i];\n const y = ys[i];\n if (!Number.isFinite(x) || !Number.isFinite(y) || x === DG.FLOAT_NULL || y === DG.FLOAT_NULL) continue;\n sumX += x;\n sumY += y;\n n++;\n }\n if (n === 0) return NaN;\n const meanX = sumX / n;\n const meanY = sumY / n;\n let num = 0;\n let denX = 0;\n let denY = 0;\n for (let i = 0; i < xs.length; i++) {\n const x = xs[i];\n const y = ys[i];\n if (!Number.isFinite(x) || !Number.isFinite(y) || x === DG.FLOAT_NULL || y === DG.FLOAT_NULL) continue;\n const dx = x - meanX;\n const dy = y - meanY;\n num += dx * dy;\n denX += dx * dx;\n denY += dy * dy;\n }\n const den = Math.sqrt(denX * denY);\n return den === 0 ? NaN : num / den;\n}\n\n/** Fractional ranks (1-based). Ties get the average of the positions they span. */\nfunction rank(arr: number[]): number[] {\n const indexed = arr.map((v, i) => ({v, i}));\n indexed.sort((a, b) => a.v - b.v);\n const ranks = new Array<number>(arr.length);\n let i = 0;\n while (i < indexed.length) {\n let j = i;\n while (j + 1 < indexed.length && indexed[j + 1].v === indexed[i].v) j++;\n const avg = (i + j) / 2 + 1; // 1-based average of positions [i..j]\n for (let k = i; k <= j; k++) ranks[indexed[k].i] = avg;\n i = j + 1;\n }\n return ranks;\n}\n\n/** Spearman = Pearson over fractional ranks. */\nexport function spearman(xs: number[], ys: number[]): number {\n return pearson(rank(xs), rank(ys));\n}\n\n/** Computes Pearson + Spearman over the filtered subset of two columns. */\nfunction computePearsonSpearman(\n df: DG.DataFrame, xName: string, yName: string,\n): {r: number; rho: number} {\n const xCol = df.col(xName);\n const yCol = df.col(yName);\n if (!xCol || !yCol) return {r: NaN, rho: NaN};\n const xRaw = xCol.getRawData() as Float32Array | Float64Array;\n const yRaw = yCol.getRawData() as Float32Array | Float64Array;\n\n const xs: number[] = [];\n const ys: number[] = [];\n for (let i = 0; i < df.rowCount; i++) {\n if (!df.filter.get(i)) continue;\n const x = xRaw[i];\n const y = yRaw[i];\n if (x === DG.FLOAT_NULL || y === DG.FLOAT_NULL) continue;\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n xs.push(x);\n ys.push(y);\n }\n return {r: pearson(xs, ys), rho: spearman(xs, ys)};\n}\n\n/**\n * Main factory — derives Numerator/Denominator Mean, plots them as a scatter\n * colored by direction, draws the y=x diagonal, and writes an inline\n * Pearson/Spearman annotation into the title.\n */\nexport function createGroupMeanCorrelation(\n df: DG.DataFrame,\n options?: {title?: string},\n): DG.ScatterPlotViewer {\n const groups = getGroups(df);\n if (!groups)\n throw new Error('Annotate experimental groups first (Proteomics | Annotate Experiment)');\n\n computeGroupMeans(df, groups);\n\n const sp = df.plot.scatter({\n x: NUMERATOR_MEAN_COL,\n y: DENOMINATOR_MEAN_COL,\n color: DIRECTION_COL,\n });\n\n // Display Name primary, Gene name fallback (Plan 02 pattern).\n const labelCol = findColumn(df, SEMTYPE.DISPLAY_NAME, ['display name']) ??\n findColumn(df, SEMTYPE.GENE_SYMBOL, ['gene name', 'gene symbol']);\n if (labelCol) {\n sp.props.labelColumnNames = [labelCol.name];\n sp.props.showLabelsFor = 'MouseOverRow';\n }\n\n // y = x diagonal reference — replace any prior diagonal so re-run doesn't stack.\n df.meta.formulaLines.items = df.meta.formulaLines.items.filter((line) => {\n const f = (line.formula ?? '') as string;\n return !(typeof f === 'string' &&\n f.includes(NUMERATOR_MEAN_COL) && f.includes(DENOMINATOR_MEAN_COL));\n });\n df.meta.formulaLines.addLine({\n formula: DIAGONAL_FORMULA,\n color: DIAGONAL_COLOR,\n width: 1,\n visible: true,\n });\n sp.props.showViewerFormulaLines = true;\n\n // Inline correlation annotation over the current filter.\n const {r, rho} = computePearsonSpearman(df, NUMERATOR_MEAN_COL, DENOMINATOR_MEAN_COL);\n const baseTitle = options?.title ?? 'Group-Mean Correlation';\n const rStr = Number.isFinite(r) ? r.toFixed(2) : 'NA';\n const rhoStr = Number.isFinite(rho) ? rho.toFixed(2) : 'NA';\n sp.setOptions({\n title: `${baseTitle} — r=${rStr} (Pearson), ρ=${rhoStr} (Spearman)`,\n xColumnLabel: `${groups.group1.name} mean (log2 intensity)`,\n yColumnLabel: `${groups.group2.name} mean (log2 intensity)`,\n } as any);\n\n return sp;\n}\n","import * as DG from 'datagrok-api/dg';\nimport {SEMTYPE} from '../utils/proteomics-types';\nimport {findColumn} from '../utils/column-detection';\nimport {GroupAssignment} from '../analysis/experiment-setup';\n\n/** Returns log2-prefixed intensity column names. */\nexport function getIntensityColumns(df: DG.DataFrame): string[] {\n return df.columns.toList()\n .filter((c) => c.semType === SEMTYPE.INTENSITY && c.name.startsWith('log2('))\n .map((c) => c.name);\n}\n\n/** Computes the mean of non-null values across columns at a given row index.\n * Returns NaN if all values are null. */\nfunction groupMean(cols: DG.Column[], rowIdx: number): number {\n let sum = 0;\n let count = 0;\n for (const col of cols) {\n if (!col.isNone(rowIdx)) {\n sum += col.get(rowIdx) as number;\n count++;\n }\n }\n return count > 0 ? sum / count : NaN;\n}\n\n/** Ensures a column exists fresh -- removes it if present, then adds a new float column. */\nfunction ensureFreshFloat(df: DG.DataFrame, name: string): DG.Column {\n if (df.columns.contains(name))\n df.columns.remove(name);\n return df.columns.addNewFloat(name);\n}\n\n/** Computes MA values (M = log2 ratio, A = average intensity) and adds M, A columns to df. */\nexport function computeMA(df: DG.DataFrame, groups: GroupAssignment): void {\n const g1Cols = groups.group1.columns.map((n) => df.col(n)!);\n const g2Cols = groups.group2.columns.map((n) => df.col(n)!);\n\n const nRows = df.rowCount;\n const mArr = new Float32Array(nRows);\n const aArr = new Float32Array(nRows);\n for (let i = 0; i < nRows; i++) {\n const g1Mean = groupMean(g1Cols, i);\n const g2Mean = groupMean(g2Cols, i);\n if (isNaN(g1Mean) || isNaN(g2Mean)) {\n mArr[i] = DG.FLOAT_NULL;\n aArr[i] = DG.FLOAT_NULL;\n } else {\n mArr[i] = g2Mean - g1Mean;\n aArr[i] = (g1Mean + g2Mean) / 2;\n }\n }\n ensureFreshFloat(df, 'M').init((i) => mArr[i]);\n ensureFreshFloat(df, 'A').init((i) => aArr[i]);\n}\n\n/** Computes a moving-average trend line for the MA plot.\n * Approximates loess by sorting on A and averaging M within a sliding window.\n * Adds an MA_trend column to df. */\nexport function computeLoessTrend(df: DG.DataFrame, windowFraction: number = 0.1): void {\n const aCol = df.col('A');\n const mCol = df.col('M');\n if (!aCol || !mCol) {\n ensureFreshFloat(df, 'MA_trend');\n return;\n }\n\n const aRaw = aCol.getRawData() as Float32Array | Float64Array;\n const mRaw = mCol.getRawData() as Float32Array | Float64Array;\n\n // Collect non-null (A, M) pairs with original row indices\n const points: {idx: number; a: number; m: number}[] = [];\n for (let i = 0; i < df.rowCount; i++) {\n if (aRaw[i] !== DG.FLOAT_NULL && mRaw[i] !== DG.FLOAT_NULL)\n points.push({idx: i, a: aRaw[i], m: mRaw[i]});\n }\n\n const trendArr = new Float32Array(df.rowCount);\n trendArr.fill(DG.FLOAT_NULL);\n\n // Guard: need at least 3 non-null points\n if (points.length < 3) {\n ensureFreshFloat(df, 'MA_trend').init((i) => trendArr[i]);\n return;\n }\n\n // Sort by A value\n points.sort((a, b) => a.a - b.a);\n\n const halfWindow = Math.max(Math.round(points.length * windowFraction / 2), 5);\n\n // For each point, compute mean M in a window centered on it, writing to trendArr\n for (let i = 0; i < points.length; i++) {\n const lo = Math.max(0, i - halfWindow);\n const hi = Math.min(points.length - 1, i + halfWindow);\n let sum = 0;\n let count = 0;\n for (let j = lo; j <= hi; j++) {\n sum += points[j].m;\n count++;\n }\n trendArr[points[i].idx] = sum / count;\n }\n\n ensureFreshFloat(df, 'MA_trend').init((i) => trendArr[i]);\n}\n\n/** Computes coefficient of variation (CV = sd/mean) on raw (non-log) intensities\n * within a group of columns. Adds cvColName and meanColName float columns to df. */\nexport function computeCV(\n df: DG.DataFrame,\n groupCols: string[],\n cvColName: string,\n meanColName: string,\n): void {\n const rawArrays = groupCols\n .map((n) => df.col(n))\n .filter((c) => c != null && c.type === DG.COLUMN_TYPE.FLOAT)\n .map((c) => c!.getRawData() as Float32Array | Float64Array);\n\n const nRows = df.rowCount;\n const cvArr = new Float32Array(nRows);\n const meanArr = new Float32Array(nRows);\n\n // Welford's online algorithm for mean + sample variance.\n // The naive `(sumSq - sum*sum/count) / (count-1)` form suffers from\n // catastrophic cancellation when the values are large and the spread\n // is small — which is exactly the regime for raw intensities (often >1e6\n // with tight biological CVs).\n for (let i = 0; i < nRows; i++) {\n let count = 0;\n let mean = 0;\n let m2 = 0;\n for (const raw of rawArrays) {\n const v = raw[i];\n if (v !== DG.FLOAT_NULL) {\n // Exponentiate log2 values back to raw intensities for CV computation\n const val = Math.pow(2, v);\n count++;\n const delta = val - mean;\n mean += delta / count;\n m2 += delta * (val - mean);\n }\n }\n if (count < 1) {\n cvArr[i] = DG.FLOAT_NULL;\n meanArr[i] = DG.FLOAT_NULL;\n } else if (count < 2) {\n cvArr[i] = DG.FLOAT_NULL;\n meanArr[i] = mean;\n } else {\n const variance = m2 / (count - 1);\n const sd = Math.sqrt(Math.max(0, variance));\n cvArr[i] = mean > 0 ? sd / mean : DG.FLOAT_NULL;\n meanArr[i] = mean;\n }\n }\n\n ensureFreshFloat(df, cvColName).init((i) => cvArr[i]);\n ensureFreshFloat(df, meanColName).init((i) => meanArr[i]);\n}\n\n/** Creates a binary missingness matrix DataFrame (1 = present, 0 = missing).\n * Includes protein ID column if available. */\nexport function createMissingnessMatrix(df: DG.DataFrame, intensityCols: string[]): DG.DataFrame {\n const columns: DG.Column[] = [];\n\n // Include protein ID column if available\n const labelCol = findColumn(df, SEMTYPE.PROTEIN_ID, ['protein id', 'accession']);\n if (labelCol)\n columns.push(labelCol.clone());\n\n // Binary columns: 1 = present, 0 = missing.\n // Write directly into a fresh Int32Array, then wrap as the column.\n for (const colName of intensityCols) {\n const srcCol = df.col(colName)!;\n const srcRaw = srcCol.type === DG.COLUMN_TYPE.FLOAT\n ? srcCol.getRawData() as Float32Array | Float64Array\n : null;\n const data = new Int32Array(df.rowCount);\n if (srcRaw) {\n for (let i = 0; i < df.rowCount; i++)\n data[i] = srcRaw[i] === DG.FLOAT_NULL ? 0 : 1;\n } else {\n for (let i = 0; i < df.rowCount; i++)\n data[i] = srcCol.isNone(i) ? 0 : 1;\n }\n columns.push(DG.Column.fromInt32Array(colName, data));\n }\n\n const result = DG.DataFrame.fromColumns(columns);\n result.name = 'Missing Values';\n return result;\n}\n\n/** Creates a long-format DataFrame with columns: ProteinId, Sample, Intensity.\n * Skips null intensity values to keep the DataFrame compact. */\nexport function unpivotIntensities(df: DG.DataFrame, intensityCols: string[]): DG.DataFrame {\n const proteinIdCol = findColumn(df, SEMTYPE.PROTEIN_ID, ['protein id', 'accession']);\n\n const ids: string[] = [];\n const samples: string[] = [];\n const intensities: number[] = [];\n\n for (let i = 0; i < df.rowCount; i++) {\n const proteinId = proteinIdCol ? (proteinIdCol.get(i) as string ?? String(i)) : String(i);\n for (const colName of intensityCols) {\n const col = df.col(colName)!;\n if (!col.isNone(i)) {\n ids.push(proteinId);\n samples.push(colName);\n intensities.push(col.get(i) as number);\n }\n }\n }\n\n const result = DG.DataFrame.fromColumns([\n DG.Column.fromStrings('ProteinId', ids),\n DG.Column.fromStrings('Sample', samples),\n DG.Column.fromFloat32Array('Intensity', new Float32Array(intensities)),\n ]);\n result.name = 'Intensity Distributions';\n return result;\n}\n\n/** Creates a sample-level DataFrame with columns: Sample, MissingPct, Group.\n * Each row represents one intensity column with its missing value percentage. */\nexport function computeMissingBarData(\n df: DG.DataFrame,\n intensityCols: string[],\n groups: GroupAssignment,\n): DG.DataFrame {\n const sampleNames: string[] = [];\n const missingPcts: number[] = [];\n const groupNames: string[] = [];\n\n const g1Set = new Set(groups.group1.columns);\n const g2Set = new Set(groups.group2.columns);\n\n for (const colName of intensityCols) {\n const col = df.col(colName)!;\n let nullCount = 0;\n for (let i = 0; i < df.rowCount; i++) {\n if (col.isNone(i))\n nullCount++;\n }\n\n sampleNames.push(colName);\n missingPcts.push((nullCount / df.rowCount) * 100);\n\n if (g1Set.has(colName))\n groupNames.push(groups.group1.name);\n else if (g2Set.has(colName))\n groupNames.push(groups.group2.name);\n else\n groupNames.push('Other');\n }\n\n const result = DG.DataFrame.fromColumns([\n DG.Column.fromStrings('Sample', sampleNames),\n DG.Column.fromFloat32Array('MissingPct', new Float32Array(missingPcts)),\n DG.Column.fromStrings('Group', groupNames),\n ]);\n result.name = 'Missing Values per Sample';\n return result;\n}\n","/**\n * Phase 16 SPC Dashboard.\n *\n * Sibling-TableView host for the runs.csv-derived DataFrame (per\n * ARCHITECTURE.md §\"Cross-DataFrame Selection\") — the dashboard NEVER docks\n * onto the protein DataFrame's view. Composes Plan 02's math + Plan 03's\n * AppData I/O into a live operator surface: instrument picker, 4 I-charts\n * + 4 MR-charts with UCL/CL/LCL formula lines, baseline status sidebar with\n * a per-metric Nelson rule toggle grid, Define / Rebuild baseline modal,\n * and drill-down to the source Project on flagged-point click.\n *\n * Pareto chart (SPC-08, P2) is Plan 16-07's deliverable — `aggregateParetoCounts`\n * lives there. The rules-tripped tag is set unconditionally so Plan 07 can\n * land as a hotfix without unwinding this plan.\n */\nimport * as grok from 'datagrok-api/grok';\nimport * as ui from 'datagrok-api/ui';\nimport * as DG from 'datagrok-api/dg';\n\nimport {\n WHEELER_D4,\n evaluateNelsonRulesAllMetrics,\n defaultRulesEnabledAllMetrics,\n classifyStatus,\n BaselineSnapshot, SpcMetrics, SpcRulesEnabled,\n} from '../analysis/spc';\nimport {\n LockedBaseline, SpcRunRow,\n loadRuns, loadBaseline, saveBaseline,\n iterativeOutlierRemoval, computeBaselineStats,\n runsToDataFrame,\n} from '../analysis/spc-storage';\n\ntype MetricKey = 'median_intensity' | 'missing_pct' | 'control_corr' | 'protein_count';\n\nconst METRIC_KEYS: MetricKey[] = [\n 'median_intensity', 'missing_pct', 'control_corr', 'protein_count',\n];\n\nconst METRIC_LABELS: Record<MetricKey, string> = {\n median_intensity: 'Median log2 intensity',\n missing_pct: 'Missing %',\n control_corr: 'Control replicate correlation',\n protein_count: 'Protein count',\n};\n\nconst FORMULA_LINE_COLORS = {\n cl: '#888888',\n bound: '#666666',\n};\n\nconst LAST_INSTRUMENT_STORAGE_KEY = 'spc.last_picked_instrument';\n\n// Five canonical false-alarm-rate disclosures per UI-SPEC §\"False-alarm-rate\".\nconst FALSE_ALARM_DISCLOSURE: Record<string, string> = {\n 'rule_1_only': 'Expected false-alarm rate at this rule set: ~0.27%. (Rule 1 only — a point beyond 3σ.)',\n 'rules_1_5': 'Expected false-alarm rate at this rule set: ~0.4%. (Rules 1 + 5 — a single point beyond 3σ, or 2 of 3 beyond 2σ.)',\n 'rules_1_5_2': 'Enabling rules 1+5+2 raises the expected false-alarm rate to ~1.1%.',\n 'rules_all_8': 'Expected false-alarm rate at this rule set: ~2.65%. Enabling all 8 rules will flag roughly 1 in 38 normal-operation runs.',\n 'rules_other': 'More rules enabled → higher false-alarm rate. The Nelson 1+5 default is calibrated for ~0.4%.',\n};\n\nfunction disclosureKey(enabled: SpcRulesEnabled): string {\n const sample = enabled.median_intensity;\n const onIds = Object.entries(sample).filter(([_, on]) => on).map(([id]) => id).sort();\n if (onIds.length === 1 && onIds[0] === 'nelson_1') return 'rule_1_only';\n if (onIds.length === 2 && onIds[0] === 'nelson_1' && onIds[1] === 'nelson_5') return 'rules_1_5';\n if (onIds.length === 3 && onIds.includes('nelson_1') && onIds.includes('nelson_5') && onIds.includes('nelson_2'))\n return 'rules_1_5_2';\n if (onIds.length === 8) return 'rules_all_8';\n return 'rules_other';\n}\n\n// =====================================================================================\n// Pure helpers — exported because they're directly testable.\n// =====================================================================================\n\nexport interface ControlLines {\n ucl: number;\n cl: number;\n lcl: number;\n}\n\n/** UCL = mean + 3sd, CL = mean, LCL = mean - 3sd. Used for the I-chart formula lines\n * AND tested by SPC:formula_lines. Returns NaN-bearing lines when the baseline\n * metric is unavailable; the caller skips formula-line addition in that case. */\nexport function computeControlLines(\n baseline: {metrics: BaselineSnapshot} | null, metric: MetricKey,\n): ControlLines {\n if (!baseline) return {ucl: NaN, cl: NaN, lcl: NaN};\n const m = baseline.metrics[metric];\n if (!m || !Number.isFinite(m.mean) || !Number.isFinite(m.sd))\n return {ucl: NaN, cl: NaN, lcl: NaN};\n return {ucl: m.mean + 3 * m.sd, cl: m.mean, lcl: m.mean - 3 * m.sd};\n}\n\nexport interface DrillDownInput {\n run_id: string;\n run_label: string;\n source_project_id: string | null;\n instrument_id?: string;\n}\n\nexport type DrillDownResult =\n | {kind: 'opened'; id: string}\n | {kind: 'toast'; message: string};\n\n/** Pure drill-down resolver. Caller injects a `projectsFind` that returns either\n * a project (with `.open()`) or null. The handler classifies into:\n * - 'opened' on success (project found + opened)\n * - 'toast' for both the null-id case AND the find()-returns-null case\n * Both toast messages are biologist-readable per UI-SPEC §\"Drill-down\". */\nexport async function resolveDrillDown(\n row: DrillDownInput,\n deps: {projectsFind: (id: string) => Promise<{open: () => any} | null>},\n): Promise<DrillDownResult> {\n if (row.source_project_id == null) {\n return {\n kind: 'toast',\n message: `Source for '${row.run_label}' is not currently available. ` +\n `Open the run's analyzed file and re-run Compute SPC Status.`,\n };\n }\n const project = await deps.projectsFind(row.source_project_id);\n if (!project) {\n return {\n kind: 'toast',\n message: `Source for '${row.run_label}' is not currently available. ` +\n `Open the run's analyzed file and re-run Compute SPC Status.`,\n };\n }\n await project.open();\n return {kind: 'opened', id: row.source_project_id};\n}\n\n// =====================================================================================\n// createSpcChartPanel — pure factory returning {iChart, mrChart}. The MR column\n// must already exist on runsDf (openSpcDashboard adds it before docking).\n// =====================================================================================\n\nexport function createSpcChartPanel(\n runsDf: DG.DataFrame,\n baseline: {metrics: BaselineSnapshot} | null,\n metric: MetricKey,\n): {iChart: DG.Viewer; mrChart: DG.Viewer} {\n const iChart: any = DG.Viewer.lineChart(runsDf, {\n xColumnName: 'acquisition_datetime',\n yColumnNames: [metric],\n title: METRIC_LABELS[metric],\n } as any);\n\n if (baseline) {\n const lines = computeControlLines(baseline, metric);\n if (Number.isFinite(lines.cl)) {\n const fl: any = iChart?.meta?.formulaLines;\n if (fl && typeof fl.addLine === 'function') {\n // Spike outcome (Plan 16-01) lands at runtime — both branches are\n // documented in the spike test; using `style:'dashed'` is the\n // expected PASS path. FAIL path is the constant-column overlay\n // fallback described in 16-RESEARCH Pattern 4.\n try {\n fl.addLine({\n formula: `\\${${metric}} = ${lines.ucl}`,\n color: FORMULA_LINE_COLORS.bound, width: 1, style: 'dashed',\n visible: true, title: 'UCL',\n });\n fl.addLine({\n formula: `\\${${metric}} = ${lines.cl}`,\n color: FORMULA_LINE_COLORS.cl, width: 1, style: 'solid',\n visible: true, title: 'CL',\n });\n fl.addLine({\n formula: `\\${${metric}} = ${lines.lcl}`,\n color: FORMULA_LINE_COLORS.bound, width: 1, style: 'dashed',\n visible: true, title: 'LCL',\n });\n } catch (_e) {\n // Spike FAIL path — formula-line API didn't honor the style. The\n // dashboard still renders; the constant-overlay fallback is\n // deferred to a follow-up if the spike returns FAIL in practice.\n }\n }\n }\n }\n\n const mrColName = `MR_${metric}`;\n const mrChart: any = DG.Viewer.lineChart(runsDf, {\n xColumnName: 'acquisition_datetime',\n yColumnNames: [mrColName],\n title: `MR ${METRIC_LABELS[metric]}`,\n } as any);\n\n if (baseline && runsDf.col(mrColName)) {\n const mrCol = runsDf.col(mrColName)!;\n let sum = 0;\n let n = 0;\n for (let i = 0; i < runsDf.rowCount; i++) {\n if (mrCol.isNone(i)) continue;\n const v = Number(mrCol.get(i));\n if (Number.isFinite(v)) { sum += v; n++; }\n }\n if (n > 0) {\n const mrMean = sum / n;\n const mrUcl = WHEELER_D4 * mrMean;\n const flMr: any = (mrChart as any)?.meta?.formulaLines;\n if (flMr && typeof flMr.addLine === 'function') {\n try {\n flMr.addLine({\n formula: `\\${${mrColName}} = ${mrUcl}`,\n color: FORMULA_LINE_COLORS.bound, width: 1, style: 'dashed',\n visible: true, title: 'MR UCL',\n });\n flMr.addLine({\n formula: `\\${${mrColName}} = ${mrMean}`,\n color: FORMULA_LINE_COLORS.cl, width: 1, style: 'solid',\n visible: true, title: 'MR CL',\n });\n } catch (_e) { /* spike FAIL fallback — same as I-chart */ }\n }\n }\n }\n\n return {iChart, mrChart};\n}\n\n// =====================================================================================\n// Pareto aggregation (SPC-08, P2) — Plan 16-07.\n// =====================================================================================\n\nexport interface ParetoEntry {\n rule: string;\n metric: string;\n count: number;\n}\n\n/** Aggregates rules-tripped trip counts across a slice of runs and returns the\n * entries sorted DESCENDING by count. Accepts an array shape (test-friendly:\n * rules_tripped as a string[]) — the dashboard caller adapts from CSV strings\n * via JSON.parse-with-try/catch before passing in. */\nexport function aggregateParetoCounts(\n runs: Array<{rules_tripped: string[]}>,\n): ParetoEntry[] {\n const counts = new Map<string, number>();\n for (const r of runs) {\n const tripped = Array.isArray(r.rules_tripped) ? r.rules_tripped : [];\n for (const t of tripped) {\n const prev = counts.get(t) ?? 0;\n counts.set(t, prev + 1);\n }\n }\n const entries: ParetoEntry[] = [];\n for (const [key, count] of counts.entries()) {\n const at = key.indexOf('@');\n if (at < 0) entries.push({rule: key, metric: '', count});\n else entries.push({rule: key.slice(0, at), metric: key.slice(at + 1), count});\n }\n entries.sort((a, b) => b.count - a.count);\n return entries;\n}\n\n/** Returns a barChart viewer ordered DESC by trip count, or null when there\n * are fewer than 4 runs (caller renders the empty-state body in that case). */\nexport function createParetoChart(\n runsDf: DG.DataFrame, instrumentId: string,\n): DG.Viewer | null {\n if (runsDf.rowCount < 4) return null;\n const rulesCol = runsDf.col('rules_tripped');\n if (!rulesCol) return null;\n const totalRuns = runsDf.rowCount;\n const inputs: Array<{rules_tripped: string[]}> = [];\n for (let i = 0; i < totalRuns; i++) {\n const raw = String(rulesCol.get(i) ?? '');\n let parsed: string[] = [];\n if (raw.length > 0) {\n try { parsed = JSON.parse(raw) as string[]; } catch { parsed = []; }\n }\n inputs.push({rules_tripped: parsed});\n }\n const entries = aggregateParetoCounts(inputs);\n if (entries.length === 0) return null;\n\n const ruleMetricCol = DG.Column.fromStrings('rule_metric',\n entries.map((e) => e.metric ? `${e.rule}@${e.metric}` : e.rule));\n const tripCountArr = new Int32Array(entries.map((e) => e.count));\n const totalRunsArr = new Int32Array(entries.map(() => totalRuns));\n const pctArr = new Float32Array(entries.map((e) => (e.count / totalRuns) * 100));\n const aggDf = DG.DataFrame.fromColumns([\n ruleMetricCol,\n DG.Column.fromInt32Array('trip_count', tripCountArr),\n DG.Column.fromInt32Array('total_runs', totalRunsArr),\n DG.Column.fromFloat32Array('pct', pctArr),\n ]);\n\n const chart: any = DG.Viewer.barChart(aggDf, {\n splitColumnName: 'rule_metric',\n valueColumnName: 'trip_count',\n title: `Which rules trip most often — ${instrumentId}`,\n } as any);\n // Axis labels per UI-SPEC §\"Pareto chart labels\".\n try {\n chart.props.xLabel = '(rule, metric)';\n chart.props.yLabel = 'Times tripped';\n } catch (_e) { /* prop names may shift across platform versions — non-fatal */ }\n return chart;\n}\n\n// =====================================================================================\n// MR column derivation (4 sibling columns on the runs df, computed once at open).\n// =====================================================================================\n\nfunction addMrColumns(runsDf: DG.DataFrame): void {\n for (const metric of METRIC_KEYS) {\n const srcCol = runsDf.col(metric);\n if (!srcCol) continue;\n const name = `MR_${metric}`;\n if (runsDf.columns.contains(name)) runsDf.columns.remove(name);\n const mr = runsDf.columns.addNewFloat(name);\n const rc = runsDf.rowCount;\n let prev: number | null = null;\n for (let i = 0; i < rc; i++) {\n if (i === 0) { mr.set(i, null); prev = null; continue; }\n if (srcCol.isNone(i) || srcCol.isNone(i - 1)) { mr.set(i, null); continue; }\n const v = Number(srcCol.get(i));\n const p = Number(srcCol.get(i - 1));\n if (!Number.isFinite(v) || !Number.isFinite(p)) { mr.set(i, null); continue; }\n mr.set(i, Math.abs(v - p));\n prev = v; void prev;\n }\n }\n}\n\n// =====================================================================================\n// Sidebar — instrument readout + baseline status + Nelson rule toggle grid\n// =====================================================================================\n\ninterface SidebarRefs {\n el: HTMLElement;\n setDisclosure: (text: string) => void;\n}\n\nfunction buildSidebar(\n instrumentId: string,\n baseline: LockedBaseline | null,\n onRebuildClick: () => void,\n onRuleToggle: (metric: MetricKey, rule: keyof SpcRulesEnabled['median_intensity'], value: boolean) => Promise<void>,\n): SidebarRefs {\n const heading = ui.h2(`Instrument: ${instrumentId}`);\n\n let statusBlock: HTMLElement;\n if (baseline) {\n statusBlock = ui.divV([\n ui.divText(`Baseline locked: ${baseline.locked_at}`),\n ui.divText(`${baseline.included_run_ids.length} runs included · ` +\n `${baseline.excluded_run_ids.length} runs excluded (3σ outlier).`),\n ui.button('Rebuild baseline...', onRebuildClick),\n ]);\n } else {\n statusBlock = ui.divV([\n ui.divText('No baseline locked yet. The dashboard turns on once a baseline exists.'),\n ]);\n }\n\n const ruleIds: Array<keyof SpcRulesEnabled['median_intensity']> = [\n 'nelson_1', 'nelson_2', 'nelson_3', 'nelson_4',\n 'nelson_5', 'nelson_6', 'nelson_7', 'nelson_8',\n ];\n\n const enabled = baseline?.rules_enabled ?? defaultRulesEnabledAllMetrics();\n const disclosure = ui.divText(FALSE_ALARM_DISCLOSURE[disclosureKey(enabled)]);\n const setDisclosure = (text: string) => { disclosure.textContent = text; };\n\n const gridRows: HTMLElement[] = [];\n gridRows.push(ui.divH([\n ui.divText(''),\n ...ruleIds.map((r) => ui.divText(r.replace('nelson_', 'R'))),\n ]));\n for (const metric of METRIC_KEYS) {\n const row: HTMLElement[] = [ui.divText(METRIC_LABELS[metric])];\n for (const rid of ruleIds) {\n const checkbox = ui.input.bool('', {\n value: enabled[metric][rid],\n tooltipText: ruleTooltip(rid),\n });\n checkbox.onChanged.subscribe(async (v: any) => {\n await onRuleToggle(metric, rid, !!v);\n });\n row.push(checkbox.root);\n }\n gridRows.push(ui.divH(row));\n }\n\n const el = ui.divV([\n heading,\n statusBlock,\n ui.h2('Nelson rules'),\n ui.divV(gridRows),\n disclosure,\n ]);\n return {el, setDisclosure};\n}\n\nfunction ruleTooltip(rule: keyof SpcRulesEnabled['median_intensity']): string {\n switch (rule) {\n case 'nelson_1': return 'Nelson rule 1: a single point beyond 3σ from the centerline.';\n case 'nelson_2': return 'Nelson rule 2: 9 consecutive points on the same side of the centerline.';\n case 'nelson_3': return 'Nelson rule 3: 6 consecutive points all trending up, or all trending down.';\n case 'nelson_4': return 'Nelson rule 4: 14 consecutive points alternating above and below the centerline.';\n case 'nelson_5': return 'Nelson rule 5: 2 out of 3 consecutive points beyond 2σ on the same side.';\n case 'nelson_6': return 'Nelson rule 6: 4 out of 5 consecutive points beyond 1σ on the same side.';\n case 'nelson_7': return 'Nelson rule 7: 15 consecutive points within 1σ of the centerline (unusually stable).';\n case 'nelson_8': return 'Nelson rule 8: 8 consecutive points more than 1σ from the centerline on either side.';\n }\n}\n\n// =====================================================================================\n// Drill-down subscription — wires the resolveDrillDown helper to a live TableView.\n// =====================================================================================\n\nfunction wireDrillDown(tv: DG.TableView, df: DG.DataFrame): void {\n tv.dataFrame.onCurrentRowChanged.subscribe(async () => {\n const i = df.currentRowIdx;\n if (i < 0) return;\n const status = String(df.col('status')?.get(i) ?? '');\n if (status !== 'flagged' && status !== 'out_of_control') return;\n const sourceRaw = df.col('source_project_id')?.get(i);\n const source = (sourceRaw == null || sourceRaw === '') ? null : String(sourceRaw);\n const result = await resolveDrillDown(\n {\n run_id: String(df.col('run_id')?.get(i) ?? ''),\n run_label: String(df.col('run_label')?.get(i) ?? ''),\n source_project_id: source,\n },\n {projectsFind: async (id: string) => {\n const p: any = await grok.dapi.projects.find(id);\n return p ? {open: () => p.open()} : null;\n }},\n );\n if (result.kind === 'toast') grok.shell.warning(result.message);\n });\n}\n\n// =====================================================================================\n// Status recomputation — invoked on every rule toggle to update point colors live.\n// =====================================================================================\n\nfunction recomputeStatusesInPlace(\n runsDf: DG.DataFrame, baseline: LockedBaseline,\n): void {\n const rowCount = runsDf.rowCount;\n if (rowCount === 0) return;\n const cols = {\n median_intensity: runsDf.col('median_intensity'),\n missing_pct: runsDf.col('missing_pct'),\n control_corr: runsDf.col('control_corr'),\n protein_count: runsDf.col('protein_count'),\n };\n const statusCol = runsDf.col('status');\n const rulesCol = runsDf.col('rules_tripped');\n if (!statusCol || !rulesCol) return;\n for (let i = 0; i < rowCount; i++) {\n const metrics: SpcMetrics = {\n median_intensity: Number(cols.median_intensity?.get(i)),\n missing_pct: Number(cols.missing_pct?.get(i)),\n control_corr: Number(cols.control_corr?.get(i)),\n protein_count: Number(cols.protein_count?.get(i)),\n sample_count: 0, computed_at: '',\n };\n const priorSeries = {\n median_intensity: [] as number[],\n missing_pct: [] as number[],\n control_corr: [] as number[],\n protein_count: [] as number[],\n };\n for (let j = 0; j < i; j++) {\n priorSeries.median_intensity.push(Number(cols.median_intensity?.get(j)));\n priorSeries.missing_pct.push(Number(cols.missing_pct?.get(j)));\n priorSeries.control_corr.push(Number(cols.control_corr?.get(j)));\n priorSeries.protein_count.push(Number(cols.protein_count?.get(j)));\n }\n const r = evaluateNelsonRulesAllMetrics(\n metrics, priorSeries, baseline.metrics, baseline.rules_enabled,\n );\n statusCol.set(i, r.status);\n rulesCol.set(i, JSON.stringify(r.rulesTripped));\n }\n void classifyStatus;\n}\n\n// =====================================================================================\n// Define / Rebuild baseline modal\n// =====================================================================================\n\nexport function showDefineBaselineDialog(\n instrumentId: string,\n runs: SpcRunRow[],\n onLocked: (baseline: LockedBaseline) => void | Promise<void>,\n existing?: LockedBaseline,\n): void {\n const isRebuild = !!existing;\n const title = isRebuild\n ? `Rebuild baseline for ${instrumentId}`\n : `Lock baseline for ${instrumentId}`;\n\n const ordered = runs.slice().sort((a, b) =>\n a.acquisition_datetime.localeCompare(b.acquisition_datetime));\n\n // Default check selection per CONTEXT.md D-04.\n const checkedSet = new Set<string>();\n if (isRebuild) {\n for (const id of existing!.included_run_ids) checkedSet.add(id);\n } else {\n const n = Math.min(7, ordered.length);\n for (let i = 0; i < n; i++) checkedSet.add(ordered[i].run_id);\n }\n\n const runCheckboxes: Array<{run: SpcRunRow; input: DG.InputBase<boolean>}> = [];\n const listEl = ui.divV([]);\n listEl.style.maxHeight = '300px';\n listEl.style.overflowY = 'auto';\n for (const r of ordered) {\n const cb = ui.input.bool('', {value: checkedSet.has(r.run_id)});\n runCheckboxes.push({run: r, input: cb});\n listEl.appendChild(ui.divH([\n cb.root,\n ui.divText(r.acquisition_datetime.slice(0, 10)),\n ui.divText(r.run_label),\n ]));\n }\n\n const iterateToggle = ui.input.bool('Iterate 3σ outlier removal (recommended)', {\n value: isRebuild ? (existing!.iteration_trace.length > 0) : true,\n tooltipText: 'When on, runs more than 3 standard deviations from the baseline mean ' +\n 'are dropped from the baseline. Capped at 2 passes.',\n });\n\n const initialEnabled: SpcRulesEnabled = existing?.rules_enabled ?? defaultRulesEnabledAllMetrics();\n const ruleIds: Array<keyof SpcRulesEnabled['median_intensity']> = [\n 'nelson_1', 'nelson_2', 'nelson_3', 'nelson_4',\n 'nelson_5', 'nelson_6', 'nelson_7', 'nelson_8',\n ];\n const ruleInputs: Record<MetricKey, Record<string, DG.InputBase<boolean>>> = {\n median_intensity: {} as any, missing_pct: {} as any,\n control_corr: {} as any, protein_count: {} as any,\n };\n const gridRows: HTMLElement[] = [\n ui.divH([ui.divText(''), ...ruleIds.map((r) => ui.divText(r.replace('nelson_', 'R')))]),\n ];\n const disclosureEl = ui.divText(FALSE_ALARM_DISCLOSURE[disclosureKey(initialEnabled)]);\n for (const metric of METRIC_KEYS) {\n const row: HTMLElement[] = [ui.divText(METRIC_LABELS[metric])];\n for (const rid of ruleIds) {\n const cb = ui.input.bool('', {\n value: initialEnabled[metric][rid],\n tooltipText: ruleTooltip(rid),\n });\n cb.onChanged.subscribe(() => {\n const snapshot = currentEnabled();\n disclosureEl.textContent = FALSE_ALARM_DISCLOSURE[disclosureKey(snapshot)];\n });\n ruleInputs[metric][rid] = cb;\n row.push(cb.root);\n }\n gridRows.push(ui.divH(row));\n }\n function currentEnabled(): SpcRulesEnabled {\n const out: any = {};\n for (const m of METRIC_KEYS) {\n out[m] = {} as any;\n for (const rid of ruleIds) out[m][rid] = !!ruleInputs[m][rid].value;\n }\n return out as SpcRulesEnabled;\n }\n\n const bodyEls: HTMLElement[] = [];\n if (isRebuild) {\n bodyEls.push(ui.divText(\n `This replaces the locked baseline from ${existing!.locked_at}. ` +\n 'The previous baseline is not kept.',\n ));\n } else {\n bodyEls.push(ui.divText('Pick the runs that represent normal operation:'));\n }\n bodyEls.push(listEl);\n bodyEls.push(iterateToggle.root);\n bodyEls.push(ui.h2('Nelson rules'));\n bodyEls.push(ui.divV(gridRows));\n bodyEls.push(disclosureEl);\n\n const dialog = ui.dialog(title);\n for (const el of bodyEls) dialog.add(el);\n dialog.onOK(async () => {\n const checked = runCheckboxes.filter((c) => c.input.value === true).map((c) => c.run);\n if (checked.length < 3) {\n grok.shell.warning('At least 3 runs must remain after outlier removal — ' +\n 'too few to compute a baseline.');\n return;\n }\n const exclusionUnion = new Set<string>();\n const traceUnion: Array<{iter: number; dropped: string[]}> = [];\n if (iterateToggle.value) {\n for (const metric of METRIC_KEYS) {\n const series = checked.map((r) => ({run_id: r.run_id, value: r[metric] as number}));\n const res = iterativeOutlierRemoval(series, 2);\n for (const id of res.excluded_run_ids) exclusionUnion.add(id);\n for (const t of res.iteration_trace) traceUnion.push(t);\n }\n }\n const retained = checked.filter((r) => !exclusionUnion.has(r.run_id));\n if (retained.length < 3) {\n grok.shell.warning('At least 3 runs must remain after outlier removal — ' +\n 'too few to compute a baseline.');\n return;\n }\n const metricsSnapshot = computeBaselineStats(retained);\n const baseline: LockedBaseline = {\n instrument_id: instrumentId,\n locked_at: new Date().toISOString(),\n included_run_ids: retained.map((r) => r.run_id),\n excluded_run_ids: Array.from(exclusionUnion),\n iteration_trace: traceUnion,\n metrics: metricsSnapshot,\n rules_enabled: currentEnabled(),\n };\n await onLocked(baseline);\n if (isRebuild) {\n grok.shell.info(`Baseline rebuilt for ${instrumentId}: ${retained.length} runs included, ` +\n `${exclusionUnion.size} excluded. Previous baseline replaced.`);\n } else {\n grok.shell.info(`Baseline locked for ${instrumentId}: ${retained.length} runs included, ` +\n `${exclusionUnion.size} excluded.`);\n }\n });\n dialog.show();\n}\n\n// =====================================================================================\n// openSpcDashboard — orchestrator\n// =====================================================================================\n\nexport async function openSpcDashboard(): Promise<void> {\n const allRuns = await loadRuns();\n if (allRuns.length === 0) {\n grok.shell.warning('No SPC runs recorded yet. Open an analyzed file, then run ' +\n 'Analyze → Compute SPC Status. The dashboard turns on once at least 4 runs have been computed.');\n return;\n }\n const instruments = Array.from(new Set(allRuns.map((r) => r.instrument_id)));\n // userDataStorage is soft-deprecated; matches v1.3 codebase (subcellular-location.ts:246).\n // Migrate to grok.userSettings as cross-cutting cleanup in v1.5.\n const lastPicked = await grok.dapi.userDataStorage.get(LAST_INSTRUMENT_STORAGE_KEY);\n const last = (lastPicked && lastPicked['instrument_id']) || instruments[0];\n const baselineByInstrument = new Map<string, LockedBaseline | null>();\n for (const inst of instruments)\n baselineByInstrument.set(inst, await loadBaseline(inst));\n\n const items = instruments.map((i) => {\n const b = baselineByInstrument.get(i);\n return b ? `${i} (baseline locked)` : `${i} (no baseline)`;\n });\n const itemToId = new Map<string, string>();\n for (let i = 0; i < instruments.length; i++) itemToId.set(items[i], instruments[i]);\n const initialItem = items[instruments.indexOf(last)] ?? items[0];\n\n const picker = ui.input.choice('Instrument', {\n value: initialItem,\n items,\n nullable: false,\n tooltipText: 'Switches the trend charts and baseline to a different instrument. ' +\n 'Only instruments with computed SPC runs are listed.',\n } as any);\n\n ui.dialog('SPC Dashboard').add(picker).onOK(async () => {\n const picked = itemToId.get(String(picker.value)) ?? instruments[0];\n // userDataStorage is soft-deprecated; matches v1.3 codebase.\n await grok.dapi.userDataStorage.put(LAST_INSTRUMENT_STORAGE_KEY,\n {instrument_id: picked});\n await openDashboardForInstrument(picked);\n }).show();\n}\n\nasync function openDashboardForInstrument(instrumentId: string): Promise<void> {\n const slice = await loadRuns(instrumentId);\n let runsDf: DG.DataFrame;\n if (slice.length === 0)\n runsDf = DG.DataFrame.create(0);\n else\n runsDf = runsToDataFrame(slice);\n runsDf.name = `SPC — ${instrumentId}`;\n addMrColumns(runsDf);\n\n const tv = grok.shell.addTableView(runsDf);\n let baseline = await loadBaseline(instrumentId);\n\n const refreshCharts = (): void => {\n for (const metric of METRIC_KEYS) {\n const {iChart, mrChart} = createSpcChartPanel(runsDf, baseline, metric);\n tv.dockManager.dock(iChart, DG.DOCK_TYPE.RIGHT, null, `I-chart ${METRIC_LABELS[metric]}`, 0.5);\n tv.dockManager.dock(mrChart, DG.DOCK_TYPE.DOWN, null, `MR-chart ${METRIC_LABELS[metric]}`, 0.5);\n }\n // SPC-08 Pareto panel (Plan 16-07). Empty-state body when slice < 4.\n const pareto = createParetoChart(runsDf, instrumentId);\n if (pareto !== null) {\n tv.dockManager.dock(pareto, DG.DOCK_TYPE.DOWN, null, 'Pareto', 0.3);\n } else {\n const empty = ui.divV([\n ui.divText('Pareto chart appears once 4 or more runs have been recorded for this instrument.'),\n ]);\n tv.dockManager.dock(empty, DG.DOCK_TYPE.DOWN, null, 'Pareto', 0.3);\n }\n };\n\n const onRebuildClick = (): void => {\n showDefineBaselineDialog(instrumentId, slice, async (newBaseline) => {\n await saveBaseline(instrumentId, newBaseline);\n baseline = newBaseline;\n recomputeStatusesInPlace(runsDf, newBaseline);\n refreshCharts();\n }, baseline ?? undefined);\n };\n\n const onRuleToggle = async (\n metric: MetricKey,\n rule: keyof SpcRulesEnabled['median_intensity'],\n value: boolean,\n ) => {\n if (!baseline) return;\n baseline.rules_enabled[metric][rule] = value;\n await saveBaseline(instrumentId, baseline);\n recomputeStatusesInPlace(runsDf, baseline);\n };\n\n const sidebar = buildSidebar(instrumentId, baseline, onRebuildClick, onRuleToggle);\n tv.dockManager.dock(sidebar.el, DG.DOCK_TYPE.LEFT, null, 'SPC Controls', 0.25);\n\n if (baseline === null) {\n const banner = ui.divV([\n ui.h2(`No baseline locked for ${instrumentId}.`),\n ui.divText('Pick the runs that represent normal operation, then click Lock baseline. ' +\n 'The dashboard turns on once a baseline exists.'),\n ui.button('Define baseline...', () => {\n showDefineBaselineDialog(instrumentId, slice, async (newBaseline) => {\n await saveBaseline(instrumentId, newBaseline);\n baseline = newBaseline;\n recomputeStatusesInPlace(runsDf, newBaseline);\n refreshCharts();\n });\n }),\n ]);\n tv.dockManager.dock(banner, DG.DOCK_TYPE.RIGHT, null, 'Baseline', 0.75);\n } else {\n refreshCharts();\n }\n\n wireDrillDown(tv, runsDf);\n}\n","import * as DG from 'datagrok-api/dg';\nimport * as ui from 'datagrok-api/ui';\nimport * as rxjs from 'rxjs';\nimport {debounceTime} from 'rxjs/operators';\nimport {findColumn} from '../utils/column-detection';\nimport {SEMTYPE, DIRECTION_COLORS_BASE, DEFAULT_FC_THRESHOLD,\n DEFAULT_P_THRESHOLD} from '../utils/proteomics-types';\nimport {parseAccession} from '../panels/uniprot-panel';\nimport {getGroups, getOrganism} from '../analysis/experiment-setup';\nimport {\n getSubcellularLocations,\n LOCATION_COLORS,\n ProgressCb,\n} from '../analysis/subcellular-location';\n\n/** -log10 of the smallest representable positive double, used as a sentinel for\n * p-values that underflow to literal 0 (e.g. from t-test extreme inputs).\n * Plotting at this height keeps the point visible but clearly off-scale,\n * rather than colliding with real values like p = 1e-10. */\nconst UNDERFLOW_NEGLOG10 = -Math.log10(Number.MIN_VALUE);\n\n/** Significance metric the volcano Y axis / classification is computed from. */\nexport type MetricKind = 'adj.p-value' | 'p-value';\n\n/** Active color dimension on the volcano (significance categories vs subcellular location). */\nexport type ColorDim = 'significance' | 'location';\n\n/** Stable, generic column names. The Y/color bindings keep these names across\n * a metric/color toggle; only the values change in place (Pitfall 5 — never\n * early-return on existence, never remove+re-add a bound column). */\nconst NEG_LOG_COL = 'negLog10P';\nconst DIRECTION_COL = 'direction';\nexport const LOCATION_COL = 'Subcellular Location';\n\n/** Persists the active metric on the DataFrame so the Volcano Options dialog\n * (G2) and the axis-label overlay (G1) can derive Y-axis text without\n * re-reading scatter props. recomputeVolcano updates this on every toggle. */\nexport const VOLCANO_METRIC_TAG = 'proteomics.volcano_metric';\n\n/** Module-level subscription store mirrors `enrichment-viewers.ts:9` —\n * disposed at the start of every createVolcanoPlot to prevent stacked\n * overlays / frozen counters on viewer re-entry (Pitfall 6). */\nlet activeVolcanoSubscriptions: rxjs.Subscription[] = [];\n\n/** Marker class on a volcano's scatter root; scopes the axis-chip-hiding\n * stylesheet so it only affects our volcanoes, never other scatterplots. */\nconst VOLCANO_ROOT_CLASS = 'proteomics-volcano';\n\n/** Injects the scoped stylesheet that hides the platform's X/Y axis\n * column-selector chips inside a volcano (they duplicated our custom axis\n * labels). `.d4-vertical` (Y) and `.d4-bottom-center` (X) only — the color\n * (`.d4-vertical-right`) and size selectors stay. Idempotent: injected once. */\nfunction ensureVolcanoStyles(): void {\n const id = 'proteomics-volcano-styles';\n if (document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n style.textContent =\n `.${VOLCANO_ROOT_CLASS} .d4-column-selector.d4-vertical,` +\n `.${VOLCANO_ROOT_CLASS} .d4-column-selector.d4-bottom-center{display:none !important;}`;\n document.head.appendChild(style);\n}\n\n/** Resolves the significance column for the requested metric. `p-value` falls\n * back to `adj.p-value` when the raw p-value column is absent (D-06 guard — no\n * throw, stays on adj.p-value). Throws only when adj.p-value itself is missing\n * (genuinely no DE result). */\nfunction pickMetricColumn(df: DG.DataFrame, metric: MetricKind): DG.Column {\n if (metric === 'p-value') {\n const p = df.col('p-value');\n if (p) return p;\n }\n const adj = df.col('adj.p-value');\n if (!adj)\n throw new Error('adj.p-value column not found');\n return adj;\n}\n\n/** Ensures the -log10(metric) column exists and reflects `metric`. The column\n * name is FIXED so the scatter Y binding is stable; values are ALWAYS re-init\n * in place so a metric toggle updates the axis without rebinding. */\nexport function ensureNegLog10Column(\n df: DG.DataFrame, metric: MetricKind = 'adj.p-value',\n): string {\n const pCol = pickMetricColumn(df, metric);\n const col = df.col(NEG_LOG_COL) ?? df.columns.addNewFloat(NEG_LOG_COL);\n col.init((i) => {\n if (pCol.isNone(i)) return DG.FLOAT_NULL;\n const p = pCol.get(i) as number;\n return p > 0 ? -Math.log10(p) : UNDERFLOW_NEGLOG10;\n });\n return NEG_LOG_COL;\n}\n\n/** LOCKED color contract (D-04, CONTEXT.md §\"Specifics\"): magenta = numerator\n * (group1), cyan = denominator (group2), gray = NS. Keys are derived per call\n * from `getGroups(df)`; the ARGB ints are the invariant base, now sourced from\n * `proteomics-types` and re-exported here for existing importers. */\nexport {DIRECTION_COLORS_BASE};\n\n/** Ensures the direction column, classified against the chosen `metric` (same\n * column the Y axis uses, so dots and coloring never disagree). Updated in\n * place — never remove+re-add (preserves viewer/grid bindings). D-04 migration:\n * category strings derive from `getGroups(df)` (`Enriched in {g1}` / `Enriched\n * in {g2}` / `Not significant`), color map is the LOCKED magenta/cyan/gray. */\nexport function ensureDirectionColumn(\n df: DG.DataFrame,\n fcThreshold: number,\n pThreshold: number,\n metric: MetricKind = 'adj.p-value',\n): string {\n const fcCol = df.col('log2FC');\n if (!fcCol)\n throw new Error('log2FC column not found');\n const pCol = pickMetricColumn(df, metric);\n\n const groups = getGroups(df);\n const g1Label = groups ? `Enriched in ${groups.group1.name}` : 'Enriched in group1';\n const g2Label = groups ? `Enriched in ${groups.group2.name}` : 'Enriched in group2';\n const nsLabel = 'Not significant';\n\n const n = df.rowCount;\n const vals: string[] = new Array(n);\n for (let i = 0; i < n; i++) {\n if (fcCol.isNone(i) || pCol.isNone(i)) { vals[i] = nsLabel; continue; }\n const fc = fcCol.get(i) as number;\n const p = pCol.get(i) as number;\n if (p <= pThreshold && fc > fcThreshold) vals[i] = g1Label;\n else if (p <= pThreshold && fc < -fcThreshold) vals[i] = g2Label;\n else vals[i] = nsLabel;\n }\n\n const col = df.col(DIRECTION_COL) ?? df.columns.addNewString(DIRECTION_COL);\n col.init((i) => vals[i]);\n col.meta.colors.setCategorical({\n [g1Label]: DIRECTION_COLORS_BASE.enrichedG1,\n [g2Label]: DIRECTION_COLORS_BASE.enrichedG2,\n [nsLabel]: DIRECTION_COLORS_BASE.notSig,\n });\n return DIRECTION_COL;\n}\n\n/** FNV-1a 32-bit hex hash. Deterministic, dependency-free, fast enough for the\n * ~8k-accession stable-sorted join that ensureLocationColumn feeds it. Used\n * only as a cache-invalidation key on the Subcellular Location column. */\nfunction fnv1aHex(s: string): string {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return h.toString(16).padStart(8, '0');\n}\n\n/** Cache-invalidation key on the Subcellular Location COLUMN (not the\n * DataFrame). This is the first column-level tag in the package — the\n * DataFrame tag convention covers whole-pipeline workflow state, while\n * per-column cache-invalidation metadata belongs on the column. Documented\n * in 13-08 SUMMARY.md as a new convention. */\nconst LOCATION_HASH_TAG = 'proteomics.location_acc_hash';\n\n/** Ensures the 'Subcellular Location' categorical column using the shared\n * verbatim-CK-omics service (13-04). Bulk-init string column, the LOCKED 11+1\n * palette via setCategorical, semType = SUBCELLULAR_LOCATION. In place.\n *\n * Short-circuits when the column already exists AND its accession-set hash\n * tag matches the current accession set — skipping the entire fetch+init\n * pipeline. The palette and semType survive on the column object across\n * the short-circuit because `col.meta.colors.setCategorical` and\n * `col.semType` are set on the same column object as last run.\n *\n * `progress` is forwarded to getSubcellularLocations for the fetch phases\n * AND fired once for the 'init-column' phase so the dialog's pi can advance\n * past the post-fetch bulk-init. */\nexport async function ensureLocationColumn(\n df: DG.DataFrame, progress?: ProgressCb,\n): Promise<string> {\n const idCol = findColumn(df, SEMTYPE.PROTEIN_ID,\n ['primary protein id', 'protein id', 'protein ids', 'accession', 'uniprot']) ??\n df.col('Primary Protein ID') ?? df.col('Protein ID');\n\n const n = df.rowCount;\n const accForRow: (string | null)[] = new Array(n).fill(null);\n const accessions = new Set<string>();\n if (idCol) {\n for (let i = 0; i < n; i++) {\n const raw = idCol.get(i) as string | null;\n const acc = raw ? parseAccession(raw) : null;\n accForRow[i] = acc;\n if (acc) accessions.add(acc);\n }\n }\n\n // Stable-sorted join → deterministic across calls regardless of row order.\n const currentHash = fnv1aHex([...accessions].sort().join('|'));\n\n const existing = df.col(LOCATION_COL);\n if (existing && existing.getTag(LOCATION_HASH_TAG) === currentHash) {\n // Short-circuit: column already populated for this exact accession set.\n // Fire 'init-column' so the dialog's pi can advance to 100% and close\n // cleanly without sitting at 0%.\n progress?.(1, 1, 'init-column');\n return LOCATION_COL;\n }\n\n // Organism (set by the enrichment dialog, persisted as a df tag) narrows the\n // gene-fallback pass so non-human data isn't mis-colored from human entries.\n const locByAcc = await getSubcellularLocations(\n [...accessions], getOrganism(df), progress);\n const vals: string[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const acc = accForRow[i];\n vals[i] = (acc && locByAcc.get(acc)) || 'Unknown';\n }\n\n const col = existing ?? df.columns.addNewString(LOCATION_COL);\n col.init((i) => vals[i]);\n col.meta.colors.setCategorical(LOCATION_COLORS);\n col.semType = SEMTYPE.SUBCELLULAR_LOCATION;\n // Column-level cache-invalidation tag — see plan 13-08 patterns-established.\n col.setTag(LOCATION_HASH_TAG, currentHash);\n // Final progress tick after bulk-init so the dialog's pi advances past\n // the network phase into 'init-column' done.\n progress?.(1, 1, 'init-column');\n return LOCATION_COL;\n}\n\n/** Replaces (never stacks) the volcano threshold lines: horizontal at the\n * significance cutoff and the ±fold-change verticals. */\nfunction applyThresholdLines(\n df: DG.DataFrame, yColName: string, fcThreshold: number, pThreshold: number,\n): void {\n const hLine = -Math.log10(pThreshold);\n const yFormulaPrefix = `\\${${yColName}}`;\n const fcFormulaPrefix = `\\${log2FC}`;\n df.meta.formulaLines.items = df.meta.formulaLines.items.filter((line) => {\n const f = line.formula ?? '';\n return !(typeof f === 'string' &&\n (f.startsWith(yFormulaPrefix) || f.startsWith(fcFormulaPrefix)));\n });\n df.meta.formulaLines.addLine(\n {formula: `${yFormulaPrefix} = ${hLine}`, color: '#888888', width: 1, visible: true});\n df.meta.formulaLines.addLine(\n {formula: `${fcFormulaPrefix} = ${fcThreshold}`, color: '#888888', width: 1, visible: true});\n df.meta.formulaLines.addLine(\n {formula: `${fcFormulaPrefix} = ${-fcThreshold}`, color: '#888888', width: 1, visible: true});\n}\n\n/** UI-SPEC §\"Copywriting\": Y-axis label depends on the active metric;\n * defaults to adj.p-value mode when the tag is absent. */\nfunction yAxisLabelForMetric(metric: MetricKind | null | undefined): string {\n return metric === 'p-value' ? '-Log10(p-value)' : '-Log10(Q-value)';\n}\n\n/** G2 dialog-preload contract: every input in the Volcano Options dialog is\n * seeded from {@link readVolcanoState}. Source-of-truth precedence:\n * 1. `sp.getOptions().look.colorColumnName` → colorDim\n * 2. `df.tag(VOLCANO_METRIC_TAG)` → metric (set by recomputeVolcano)\n * Pitfall 2 — the dialog snapshots at open time; OK uses input values, never\n * a re-read of sp.getOptions. */\nexport interface VolcanoState {\n metric: MetricKind;\n colorDim: ColorDim;\n}\n\nexport function readVolcanoState(df: DG.DataFrame, sp: DG.ScatterPlotViewer): VolcanoState {\n const opts = sp.getOptions() as any;\n const look = opts?.look ?? {};\n const colorDim: ColorDim = look.colorColumnName === LOCATION_COL ? 'location' : 'significance';\n const metric = (df.getTag(VOLCANO_METRIC_TAG) as MetricKind | null) ?? 'adj.p-value';\n return {metric, colorDim};\n}\n\n/** Volcano title synthesis from `proteomics.groups` per UI-SPEC §\"Copywriting\":\n * `Volcano Plot: {g1} vs {g2}`, or `Volcano Plot` when groups are unset. */\nfunction synthesizeVolcanoTitle(df: DG.DataFrame): string {\n const groups = getGroups(df);\n return groups ?\n `Volcano Plot: ${groups.group1.name} vs ${groups.group2.name}` :\n 'Volcano Plot';\n}\n\n/** Disposes every subscription in `activeVolcanoSubscriptions` and removes any\n * axis-label / counter overlays attached to `sp.root`. Called at the start of\n * every createVolcanoPlot so re-entry never stacks DOM or strands subscribers\n * pointing at a detached viewer (Pitfall 6). */\nfunction disposeVolcanoAttachments(sp?: DG.ScatterPlotViewer): void {\n for (const s of activeVolcanoSubscriptions) s.unsubscribe();\n activeVolcanoSubscriptions = [];\n if (sp) {\n for (const sel of [\n '[data-volcano-axis-x]', '[data-volcano-axis-y]', '[data-volcano-counter]',\n '[data-volcano-busy]',\n ])\n sp.root.querySelectorAll(sel).forEach((el) => el.remove());\n }\n}\n\n/** Re-reads the Y-axis label DOM (if present) from the current metric tag.\n * Called by recomputeVolcano after the tag is persisted so the label reflects\n * the new metric immediately (sp.onPropertyChanged doesn't fire when only the\n * tag changes — the yColumnName stays stable). */\nfunction refreshVolcanoAxisLabel(sp: DG.ScatterPlotViewer, df: DG.DataFrame): void {\n const yLabel = sp.root.querySelector<HTMLElement>('[data-volcano-axis-y]');\n if (yLabel) {\n const metric = df.getTag(VOLCANO_METRIC_TAG) as MetricKind | null;\n yLabel.textContent = yAxisLabelForMetric(metric);\n }\n}\n\n/** D-06 live counter overlay: floating div anchored bottom-right of the\n * volcano. Heading + Total + per-category counts (significance categories\n * when color = direction, subcellular location categories when color =\n * Subcellular Location). Counts iterate `df.filter` only (selection toggles\n * trigger a recompute defensively but never change the displayed counts —\n * CONTEXT D-06). Subscriptions are pushed into `activeVolcanoSubscriptions`\n * so disposeVolcanoAttachments tears them down on re-entry (Pitfall 6). */\nfunction attachCounterOverlay(sp: DG.ScatterPlotViewer, df: DG.DataFrame): void {\n const host = sp.root;\n host.style.position = host.style.position || 'relative';\n\n const overlay = ui.divV([]);\n overlay.dataset.volcanoCounter = 'true';\n Object.assign(overlay.style, {\n position: 'absolute', bottom: '8px', right: '8px',\n padding: '8px 16px', background: 'rgba(255,255,255,0.85)',\n borderRadius: '4px', fontSize: '0.9em',\n pointerEvents: 'none', zIndex: '5',\n } as Partial<CSSStyleDeclaration>);\n host.appendChild(overlay);\n\n const recompute = (): void => {\n const total = df.filter.trueCount;\n const colorColName = sp.props.colorColumnName;\n const colorCol = colorColName ? df.col(colorColName) : null;\n\n // Iterate categories from the column's own category list so zero-count\n // categories still render (D-06: empty filter still shows zeros, not\n // just the categories present in the filtered subset).\n const counts = new Map<string, number>();\n let perCategoryEnabled = false;\n if (colorCol && (colorColName === DIRECTION_COL || colorColName === LOCATION_COL)) {\n perCategoryEnabled = true;\n for (const cat of colorCol.categories) counts.set(cat, 0);\n for (let i = 0; i < df.rowCount; i++) {\n if (!df.filter.get(i)) continue;\n if (colorCol.isNone(i)) continue;\n const cat = colorCol.get(i) as string;\n counts.set(cat, (counts.get(cat) ?? 0) + 1);\n }\n }\n\n overlay.replaceChildren();\n const heading = ui.divText('Visible Proteins');\n heading.style.fontWeight = 'bold';\n overlay.appendChild(heading);\n overlay.appendChild(ui.divText(`Total: ${total.toLocaleString()}`));\n if (perCategoryEnabled) {\n for (const [cat, n] of counts)\n overlay.appendChild(ui.divText(`${cat}: ${n.toLocaleString()}`));\n }\n };\n\n recompute();\n activeVolcanoSubscriptions.push(\n df.onFilterChanged.pipe(debounceTime(50)).subscribe(recompute),\n df.onSelectionChanged.pipe(debounceTime(50)).subscribe(recompute),\n sp.onPropertyValueChanged.pipe(debounceTime(50)).subscribe(recompute),\n );\n}\n\n/** Attaches DOM overlays for X and Y axis labels (the scatter has no\n * xAxisCustomTitle / yAxisCustomTitle prop). X label is invariant; Y label is\n * driven from VOLCANO_METRIC_TAG and re-rendered by refreshVolcanoAxisLabel. */\nfunction attachAxisLabels(sp: DG.ScatterPlotViewer, df: DG.DataFrame): void {\n const host = sp.root;\n host.style.position = host.style.position || 'relative';\n\n const xLabel = ui.divText('Log2 Fold Change');\n xLabel.dataset.volcanoAxisX = 'true';\n Object.assign(xLabel.style, {\n position: 'absolute', bottom: '4px', left: '50%',\n transform: 'translateX(-50%)', fontSize: '0.85em',\n pointerEvents: 'none', background: 'rgba(255,255,255,0.7)',\n padding: '0 4px', zIndex: '4',\n } as Partial<CSSStyleDeclaration>);\n host.appendChild(xLabel);\n\n const metric = df.getTag(VOLCANO_METRIC_TAG) as MetricKind | null;\n const yLabel = ui.divText(yAxisLabelForMetric(metric));\n yLabel.dataset.volcanoAxisY = 'true';\n Object.assign(yLabel.style, {\n position: 'absolute', left: '4px', top: '50%',\n transform: 'translateY(-50%) rotate(-90deg)',\n transformOrigin: 'left center', fontSize: '0.85em',\n pointerEvents: 'none', background: 'rgba(255,255,255,0.7)',\n padding: '0 4px', zIndex: '4',\n } as Partial<CSSStyleDeclaration>);\n host.appendChild(yLabel);\n\n // Defensive: refresh on any property change as a secondary trigger\n // (recomputeVolcano calls refreshVolcanoAxisLabel directly — this catches\n // any external prop edit, e.g. user changes color column via property panel).\n activeVolcanoSubscriptions.push(\n sp.onPropertyValueChanged.pipe(debounceTime(50))\n .subscribe(() => refreshVolcanoAxisLabel(sp, df)),\n );\n}\n\n/** 13-10 in-volcano busy overlay. Centered card on `sp.root` showing a phase\n * label and an optional detail line; updated per ProgressCb tick from the\n * caller (e.g. volcanoOptions during a first-time subcellular-location fetch).\n *\n * The TaskBarProgressIndicator at the bottom of the platform shell is too easy\n * to miss while the user stares at a stale-looking volcano (post-13-08 UAT\n * Test 3). This overlay anchors progress on the surface the user is actually\n * watching. Tagged with `data-volcano-busy` so disposeVolcanoAttachments\n * sweeps it on createVolcanoPlot re-entry. */\nexport function showVolcanoBusy(sp: DG.ScatterPlotViewer, label: string): void {\n // Idempotent: replace any pre-existing overlay rather than stacking.\n hideVolcanoBusy(sp);\n\n const host = sp.root;\n host.style.position = host.style.position || 'relative';\n\n const overlay = ui.divV([]);\n overlay.dataset.volcanoBusy = 'true';\n Object.assign(overlay.style, {\n position: 'absolute', top: '50%', left: '50%',\n transform: 'translate(-50%, -50%)',\n padding: '12px 20px', background: 'rgba(255,255,255,0.95)',\n border: '1px solid #ccc', borderRadius: '6px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n fontSize: '0.95em', textAlign: 'center',\n pointerEvents: 'none', zIndex: '6',\n maxWidth: '320px',\n } as Partial<CSSStyleDeclaration>);\n\n const labelDiv = ui.divText(label);\n labelDiv.style.fontWeight = 'bold';\n labelDiv.style.marginBottom = '4px';\n const detailDiv = ui.divText('');\n detailDiv.style.fontSize = '0.85em';\n detailDiv.style.color = '#666';\n overlay.appendChild(labelDiv);\n overlay.appendChild(detailDiv);\n host.appendChild(overlay);\n}\n\nexport function updateVolcanoBusy(\n sp: DG.ScatterPlotViewer, label: string, detail?: string,\n): void {\n const overlay = sp.root.querySelector<HTMLElement>('[data-volcano-busy]');\n if (!overlay) return; // already torn down — caller raced detach\n const [labelDiv, detailDiv] = Array.from(overlay.children) as HTMLElement[];\n if (labelDiv) labelDiv.textContent = label;\n if (detailDiv) detailDiv.textContent = detail ?? '';\n}\n\nexport function hideVolcanoBusy(sp: DG.ScatterPlotViewer): void {\n sp.root.querySelectorAll('[data-volcano-busy]').forEach((el) => el.remove());\n}\n\n/** Column that drives the volcano's point labels. Sparse: it holds the chosen\n * display name only for the labeled rows and '' everywhere else. `~`-prefixed so\n * it stays out of the grid. Labels bind to THIS column (showLabelsFor='All')\n * instead of to df.selection, so labeling no longer hijacks the user's selection\n * — that coupling surfaced as the confusing orange \"N selected\" on open and let\n * the enrichment cross-link wipe the labels. */\nexport const VOLCANO_LABEL_COL = '~Volcano label';\n/** Persisted top-N label count so the options dialog + search path can read it. */\nexport const VOLCANO_TOPN_TAG = 'proteomics.volcano_top_n';\n\n/** Optional pinned axis maxima, stored as df tags so they survive the metric /\n * color toggles that re-enter recomputeVolcano (tag-based state, like the metric\n * and top-N). Empty = auto-scale. X is the symmetric |log2FC| bound (pins\n * xMin=-xMax, xMax=+xMax); Y pins the −log10(p) maximum with yMin at 0. Lets\n * analysts fix identical axes across contrasts for side-by-side comparison\n * (CK x_max_var / y_max_var). */\nexport const VOLCANO_XMAX_TAG = 'proteomics.volcano_x_max';\nexport const VOLCANO_YMAX_TAG = 'proteomics.volcano_y_max';\n\n/** Reads the pinned axis maxima; a tag that is absent, non-numeric, or ≤ 0 reads\n * as null (auto-scale). */\nexport function getVolcanoAxisMax(df: DG.DataFrame): {xMax: number | null; yMax: number | null} {\n const parse = (tag: string): number | null => {\n const v = parseFloat(df.getTag(tag) ?? '');\n return Number.isFinite(v) && v > 0 ? v : null;\n };\n return {xMax: parse(VOLCANO_XMAX_TAG), yMax: parse(VOLCANO_YMAX_TAG)};\n}\n\n/** Persists the pinned axis maxima; null / non-positive clears the tag (auto). */\nexport function setVolcanoAxisMax(df: DG.DataFrame, xMax: number | null, yMax: number | null): void {\n const write = (tag: string, v: number | null) =>\n df.setTag(tag, v != null && Number.isFinite(v) && v > 0 ? String(v) : '');\n write(VOLCANO_XMAX_TAG, xMax);\n write(VOLCANO_YMAX_TAG, yMax);\n}\n\n/** Applies the pinned axis bounds from the df tags onto the scatterplot. When a\n * bound is unset, resets that axis to the data's actual min/max (a fit-to-data\n * reset) rather than NaN — the platform rejects a NaN viewport (\"Viewport can't\n * be infinite\"). Called by createVolcanoPlot and every recomputeVolcano so a\n * metric / color toggle keeps the pinned axes. */\nexport function applyVolcanoAxisBounds(sp: DG.ScatterPlotViewer, df: DG.DataFrame): void {\n const {xMax, yMax} = getVolcanoAxisMax(df);\n if (xMax != null) {\n sp.props.xMin = -xMax;\n sp.props.xMax = xMax;\n } else {\n const fc = df.col('log2FC');\n if (fc != null && Number.isFinite(fc.min) && Number.isFinite(fc.max)) {\n const pad = Math.max((fc.max - fc.min) * 0.05, 1e-6);\n sp.props.xMin = fc.min - pad;\n sp.props.xMax = fc.max + pad;\n }\n }\n if (yMax != null) {\n sp.props.yMin = 0;\n sp.props.yMax = yMax;\n } else {\n const y = df.col(NEG_LOG_COL);\n if (y != null && Number.isFinite(y.max)) {\n sp.props.yMin = 0;\n sp.props.yMax = y.max * 1.05 + 1e-6;\n }\n }\n}\n\n/** Display Name (Plan 14-01) is canonical; Gene name is the pre-14-01 fallback. */\nfunction findLabelSource(df: DG.DataFrame): DG.Column | null {\n return findColumn(df, SEMTYPE.DISPLAY_NAME, ['display name']) ??\n findColumn(df, SEMTYPE.GENE_SYMBOL, ['gene name', 'gene symbol']);\n}\n\n/** Ranks filtered-in rows by significance (−log10p desc, |log2FC| desc) and\n * returns the top-N row indices. Excludes FLOAT_NULL on either axis. */\nfunction topNBySignificance(df: DG.DataFrame, n: number): number[] {\n if (n <= 0) return [];\n const yCol = df.col(NEG_LOG_COL);\n const fcCol = df.col('log2FC');\n if (!yCol || !fcCol) return [];\n const yRaw = yCol.getRawData() as Float32Array | Float64Array;\n const fcRaw = fcCol.getRawData() as Float32Array | Float64Array;\n\n const candidates: number[] = [];\n for (let i = 0; i < df.rowCount; i++) {\n if (!df.filter.get(i)) continue;\n if (yRaw[i] === DG.FLOAT_NULL || fcRaw[i] === DG.FLOAT_NULL) continue;\n candidates.push(i);\n }\n candidates.sort((a, b) => {\n const dy = yRaw[b] - yRaw[a]; // higher -log10(p) first\n if (dy !== 0) return dy;\n return Math.abs(fcRaw[b]) - Math.abs(fcRaw[a]);\n });\n return candidates.slice(0, n);\n}\n\n/** Reads the persisted top-N label count (default 15). */\nexport function getVolcanoTopN(df: DG.DataFrame): number {\n const n = parseInt(df.getTag(VOLCANO_TOPN_TAG) ?? '', 10);\n return Number.isFinite(n) && n >= 0 ? n : 15;\n}\n\n/** D-03 top-N point labels — decoupled from df.selection (Pitfall: selection-as-\n * labels conflated the orange highlight with the label set and let the\n * enrichment cross-link wipe it). Populates the sparse {@link VOLCANO_LABEL_COL}\n * with the top-N proteins by significance (plus any `extraRows`, e.g. search\n * matches), '' everywhere else, and binds it as the scatter's label source. The\n * user's selection is never touched. `n=0` with no `extraRows` clears labels. */\nexport function applyTopNLabels(\n df: DG.DataFrame,\n sp: DG.ScatterPlotViewer,\n n: number = 15,\n extraRows?: Iterable<number>,\n): void {\n df.setTag(VOLCANO_TOPN_TAG, String(n));\n const src = findLabelSource(df);\n if (!src) return; // nothing to label with → don't add an empty technical column\n\n // ensureFreshFloat-style idempotency: reuse the column if present, else add.\n const labelCol = df.col(VOLCANO_LABEL_COL) ?? df.columns.addNewString(VOLCANO_LABEL_COL);\n\n const show = new Set<number>(topNBySignificance(df, n));\n if (extraRows) for (const i of extraRows) show.add(i);\n\n // Bulk init (memory feedback_dg_column_bulk_init — never per-row set).\n labelCol.init((i) => show.has(i) ? String(src.get(i) ?? '') : '');\n\n sp.props.labelColumnNames = [VOLCANO_LABEL_COL];\n sp.props.showLabelsFor = 'All';\n}\n\n/** Creates a volcano plot (ScatterPlotViewer). Defaults match the client\n * CK-omics figure: metric = adj.p-value, color = significance (magenta/cyan/\n * gray per D-04). G1 title is synthesized from `proteomics.groups`, D-03\n * top-N labels are seeded into `df.selection`, label binding prefers\n * `Display Name` (Plan 14-01 contract) with `Gene name` as a graceful fallback\n * for DataFrames predating Plan 14-01. */\nexport function createVolcanoPlot(\n df: DG.DataFrame,\n options?: {fcThreshold?: number; pThreshold?: number; topNLabels?: number; title?: string},\n): DG.ScatterPlotViewer {\n const fcThreshold = options?.fcThreshold ?? DEFAULT_FC_THRESHOLD;\n const pThreshold = options?.pThreshold ?? DEFAULT_P_THRESHOLD;\n\n // Re-entry contract — dispose every overlay / subscription from a prior\n // createVolcanoPlot call BEFORE attaching new ones (Pitfall 6). We do this\n // again AFTER the new sp is built (with sp passed in) so any orphan DOM on\n // the new sp.root from a previous render is cleared too.\n disposeVolcanoAttachments();\n\n const initialMetric: MetricKind = (df.getTag(VOLCANO_METRIC_TAG) as MetricKind | null) ?? 'adj.p-value';\n df.setTag(VOLCANO_METRIC_TAG, initialMetric);\n\n const yColName = ensureNegLog10Column(df, initialMetric);\n const colorColName = ensureDirectionColumn(df, fcThreshold, pThreshold, initialMetric);\n\n const sp = df.plot.scatter({\n x: 'log2FC',\n y: yColName,\n color: colorColName,\n });\n\n applyThresholdLines(df, yColName, fcThreshold, pThreshold);\n sp.props.showViewerFormulaLines = true;\n\n // Hide the platform's interactive axis column-selector chips. They render the\n // raw column name ('log2FC' / 'negLog10P') next to each axis and collided with\n // our custom rotated axis labels below (the two overlapping Y titles the fix\n // targets). The `showXSelector`/`showYSelector` props don't suppress them on\n // the current runtime, so we hide the chips with a scoped stylesheet keyed off\n // a marker class; the color/size selectors and canvas ticks are untouched.\n // attachAxisLabels supplies the sole, pretty axis titles.\n ensureVolcanoStyles();\n sp.root.classList.add(VOLCANO_ROOT_CLASS);\n\n // G1 title synthesis — runs AFTER any caller-passed options.title so the\n // contract is the synthesized string. Callers that need an explicit title\n // can read the synthesized value back via sp.getOptions().look.title.\n const title = options?.title ?? synthesizeVolcanoTitle(df);\n sp.setOptions({title});\n\n attachAxisLabels(sp, df);\n attachCounterOverlay(sp, df);\n applyVolcanoAxisBounds(sp, df);\n\n // D-03 (decoupled): label the top-N by significance via the sparse label\n // column — NOT via df.selection. topNLabels=0 opts out (no labels).\n applyTopNLabels(df, sp, options?.topNLabels ?? 15);\n\n return sp;\n}\n\n/** Single synchronized recompute: re-runs the metric-parameterized Y and\n * direction helpers and the threshold lines together, then points the scatter\n * at the chosen color dimension. After a Q↔P toggle the Y values, up/down/NS\n * classes and the threshold line all move together — they never disagree.\n * `colorDim`: 'significance' → direction column, 'location' → the locked\n * Subcellular-Location palette. `metric` 'p-value' is guarded (falls back to\n * adj.p-value when the column is absent). */\nexport async function recomputeVolcano(\n df: DG.DataFrame,\n sp: DG.ScatterPlotViewer,\n metric: MetricKind,\n colorDim: ColorDim,\n fcThreshold = DEFAULT_FC_THRESHOLD,\n pThreshold = DEFAULT_P_THRESHOLD,\n progress?: ProgressCb,\n): Promise<void> {\n // Persist BEFORE the column-recompute path so the axis-label refresh below\n // sees the new metric. The tag is the single source of truth for G2.\n df.setTag(VOLCANO_METRIC_TAG, metric);\n\n const yName = ensureNegLog10Column(df, metric);\n const dirName = ensureDirectionColumn(df, fcThreshold, pThreshold, metric);\n applyThresholdLines(df, yName, fcThreshold, pThreshold);\n\n sp.props.xColumnName = 'log2FC';\n sp.props.yColumnName = yName;\n if (colorDim === 'location')\n sp.props.colorColumnName = await ensureLocationColumn(df, progress);\n else\n sp.props.colorColumnName = dirName;\n\n refreshVolcanoAxisLabel(sp, df);\n applyVolcanoAxisBounds(sp, df);\n}\n","module.exports = DG;","module.exports = grok;","module.exports = rxjs;","module.exports = rxjs.operators;","module.exports = ui;","// 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].call(module.exports, 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 = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (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 = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (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};","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(110);\n"],"names":["DG","DataFrame","fromCsv","columns","add","Column","fromList","TYPE","BYTE_ARRAY","Array","from","Uint8Array","assure","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","then","apply","ms","this","r","setTimeout","awaitCheck","checkHandler","error","wait","interval","clearInterval","intervalId","Error","setInterval","console","log","bind","info","warn","notNull","name","fromColumns","fromStrings","module","exports","n","i","s","u","a","o","c","f","h","d","l","$","y","M","weekdays","split","months","ordinal","t","m","String","length","join","v","z","utcOffset","Math","abs","floor","date","year","month","clone","ceil","p","w","D","Q","toLowerCase","replace","g","S","_","O","args","arguments","b","locale","$L","utc","$u","x","$x","$offset","parse","prototype","$d","Date","NaN","test","match","substring","UTC","init","$y","getFullYear","$M","getMonth","$D","getDate","$W","getDay","$H","getHours","$m","getMinutes","$s","getSeconds","$ms","getMilliseconds","$utils","isValid","toString","isSame","startOf","endOf","isAfter","isBefore","$g","set","unix","valueOf","getTime","toDate","slice","$locale","weekStart","$set","min","daysInMonth","get","Number","round","subtract","format","invalidDate","meridiem","monthsShort","weekdaysMin","weekdaysShort","getTimezoneOffset","diff","toJSON","toISOString","toUTCString","k","forEach","extend","$i","isDayjs","en","Ls","__esModule","digestLength","blockSize","K","Uint32Array","hashBlocks","pos","len","j","t1","t2","Hash","state","Int32Array","temp","buffer","bufferLength","bytesHashed","finished","reset","clean","update","data","dataLength","dataPos","finish","out","left","bitLenHi","bitLenLo","padLength","digest","_saveState","_restoreState","HMAC","key","inner","outer","pad","istate","ostate","hash","hmac","fillBuffer","counter","num","hkdfSalt","hkdf","salt","okm","hmac_","bufpos","fill","pbkdf2","password","iterations","dkLen","prf","ctr","dk","factory","sha256","jStat","undefined","concat","Object","calcRdx","val","pow","LOG10E","isArray","arg","call","isFunction","isNumber","_init","retZero","retOne","retIdent","fn","map","seq","toArray","constructor","utils","toVector","arr","_random_fn","random","setRandom","TypeError","obj","rows","cols","dimensions","row","index","rowa","col","submat","arange","ind","column","cola","diag","nrow","res","antidiag","transpose","objArr","push","func","toAlter","ncol","cumreduce","alter","create","zeros","ones","rand","identity","symmetric","size","clear","max","cnt","hival","current","start","end","rl","_slice","list","copy","rcSlice","colSlice","rowSlice","sliceAssign","A","B","nl","ml","diagonal","diagArray","mat","jProto","sort","splice","funcs","passfunc","results","self","ascNum","clip","sum","sumsqrd","sumsqerr","tmp","mean","sumrow","product","prod","low","high","unique","_arr","meansqerr","geomean","logs","meanOfLogs","exp","median","arrlen","cumsum","cumprod","diffs","arrLen","rank","distinctNumbers","numberCounts","number","sortedDistinctNumbers","numberRanks","currentRank","count","mode","maxCount","numMaxCount","mode_arr","range","variance","flag","pooledvariance","reduce","samples","deviation","dev","stdev","sqrt","pooledstdev","meandev","meddev","coeffvar","quartiles","quantiles","quantilesArray","alphap","betap","aleph","gamma","sortedArray","quantileVals","percentile","exclusive","realIndex","parseInt","frac","percentileOfScore","score","kind","strict","histogram","binCnt","first","binWidth","bins","covariance","arr1","arr2","arr1Len","sq_dev","corrcoeff","spearmancoeff","stanMoment","mu","sigma","skewSum","skewness","kurtosis","fullbool","tmpthis","callbackFunction","argsToPass","curriedFunction","vector","gammaln","xx","cof","ser","loggam","x0","x2","xp","gl","gl0","PI","gammafn","yi","q","fact","xden","xnum","Infinity","sin","gammap","lowRegGamma","an","aln","ap","del","ITMAX","factorialln","factorial","combination","combinationln","permutation","betafn","betaln","betacf","m2","aa","fpmin","qab","qap","qam","gammapinv","pp","lna1","afac","a1","gln","erf","ty","isneg","dd","erfc","erfcinv","err","ibetainv","lna","lnb","al","b1","ibeta","bt","randn","randg","shape","a2","oalph","betinc","eps","c9","a0","b0","m9","tukeyWprob","rr","cc","xleg","aleg","qsqz","wincr","pr_w","normal","cdf","blb","binc","bub","einsum","cc1","wi","elsum","jj","ac","qexpo","rinsum","_a","_b","_c","newthis","sample","vals","fnfunc","beta","pdf","alpha","inv","centralF","df1","df2","binomial","cauchy","local","scale","atan","tan","chisquare","dof","exponential","rate","invgamma","kumaraswamy","lognormal","noncentralt","ncp","studentt","tol","flip","prob","lastvalue","std","pareto","SQRT2","dof2","weibull","uniform","betacdf","negbin","hypgeom","N","scaledPDF","samplesDone","scaledCDF","factor","poisson","sumarr","sampleSmall","L","sampleLarge","U","V","slam","loglam","invalpha","vr","us","lam","triangular","arcsine","asin","cos","laplace","tukey","nmeans","df","xlegq","alegq","isFinite","ulen","f2","f2lf","f21","ff4","ans","otsum","twa1","x1","ps","tukeyQinv","valx0","valx1","iter","isUsable","divide","multiply","nrescols","rescols","dot","right","norm","nnorm","isNaN","angle","acos","aug","newarr","gauss_jordan","det","determinant","submatrix","sign","gauss_elimination","maug","pivot","y2","maxrow","triaUpSolve","parts","matrix_mode","triaLowSolve","lu","R","cholesky","T","gauss_jacobi","xv","xk","gauss_seidel","SOR","householder","QR","lstsq","array_mode","attrs","Q1","RI","I","Aj","cAi","Ij","cIi","R_I","Q2","jacobi","maxim","theta","condition","ev","rungekutta","t_j","u_j","order","k1","k2","k3","romberg","h1","richardson","X","y1","h_min","simpson","hermite","F","dF","dl","lagrange","cubic_spline","sq","gauss_quadrature","PCA","temp1","Bt","temp2","Y","C","Vt","differenceOfProportions","p1","n1","p2","n2","pooled","zscore","ztest","sides","tscore","ttest","anovafscore","expVar","sampMean","sampSampMean","tmpargs","unexpVar","anovaftest","ftest","fscore","anovaftes","qscore","mean1","mean2","sd","qtest","tukeyhsd","arrays","means","normalci","change","tci","significant","pvalue","oneSidedDifferenceOfProportions","twoSidedDifferenceOfProportions","models","ols","endog","exog","nobs","df_model","df_resid","coef","predict","resid","ybar","SSE","SSR","SST","R2","t_test","model","var_count","subModelList","endog_index","exog_index","filter","sigmaHat","seBetaHat","mod","tStatistic","pValue","leftppf","interval95","se","F_statistic","F_test","adjust_R2","buildxmatrix","matrixRows","builddxmatrix","buildjxmatrix","jMat","pass","buildymatrix","array","buildjymatrix","matrixmult","regress","jMatX","jMatY","innerinv","xtranspxinv","xtransp","regresst","compile","jMatYBar","yBar","yAverage","anova","residuals","ssr","msr","sse","mse","sst","mst","r2","fratio","rmse","r2adj","stats","sds","ts","covar","xtranspx","matrixsubtract","ArrayUtils","tTest","sample1","sample2","devKnown","devEqual","variance1","variance2","length1","length2","pMore","pLess","pTot","sampleVariance1","sampleVariance2","criticalValue","totalVariance","indexesOf","values","indexes","genRange","begin","endExclusive","nItems","series","argSort","reverse","sortfn","_operations","requireDifferentialExpression","message","getTag","warning","getGroupValues","colNames","rowIdx","byName","isNone","runDifferentialExpression","group1Cols","group2Cols","group1Name","group2Name","fcThreshold","pThreshold","nRows","rowCount","fcArr","Float32Array","pArr","adjArr","testableIndices","rawPValues","vals1","vals2","pVal","corrected","pvals","method","isSorted","pvalsSorted","pvalsSortind","cm","_argsort","ecdffactor","_ecdf","includes","_cm","op","_factor","rejectmax","pvalsCorrected","_vfactor","__","_minimumAccumulate","pvalsCorrected_","_give","reject_","_giveb","fdrcorrection","log2fcCol","addNewFloat","pValCol","adjPValCol","addNewBool","adjP","fc","semType","LOG2FC","P_VALUE","setTag","fireValuesChanged","tested","untestable","buildExpressionDf","allCols","raw","getRawData","buf","fromFloat32Array","copyDEResultsToFrame","fcRaw","pRaw","aRaw","rSig","rowCol","target","rowRaw","log2fcBuf","pBuf","aBuf","sigArr","sigCount","async","runLimmaDE","exprDf","nGroup1","showDEDialog","onComplete","groups","g1","group1","g2","group2","infoText","pairs","comparisonInput","choice","g1Name","g2Name","items","nullable","hintDiv","style","cssText","updateHint","isReversed","numerator","denominator","textContent","onChanged","subscribe","methodInput","setTooltip","defaultPeptideCol","toList","find","peptideColInput","table","type","INT","FLOAT","peptideRow","root","display","fcInput","float","pInput","onOK","reversed","numeratorCols","denominatorCols","pi","denominatorName","numeratorName","pepCol","peptideCountCol","peptideDf","countCol","addNewInt","runDeqmsDE","deqmsErr","limmaErr","close","show","showEnrichmentInputExportDialog","log2fc","countDiv","updateCount","total","toLocaleString","csv","counts","idCol","geneName","proteinId","geneForRow","Map","upGenes","downGenes","background","esc","up","down","buildEnrichmentInputsCsv","base","download","GPROFILER_BASE","fetchWithTimeout","url","options","timeoutMs","proxied","fetchProxy","timeout","resp","race","ok","status","gGOSt","queryGenes","backgroundGenes","organism","sources","threshold","headers","body","JSON","stringify","query","user_threshold","significance_threshold_method","domain_scope","all_results","ordered","no_evidences","combined","measure_underrepresentation","no_iea","numeric_ns","output","json","GENERIC_PARENT_TERMS","SPECIFIC_CHILD_TERMS","applySmartPathwayFilter","maxPerSource","kept","droppedParents","cappedAtN","goBp","source","other","filteredGoBp","sorted","p_value","some","existing","otherCapped","buildEnrichmentDf","direction","memberGeneStrs","intersections","members","lim","sourceCol","addNewString","termIdCol","termNameCol","fdrCol","geneCountCol","geneRatioCol","intersectionCol","native","intersection_size","precision","fdrRaw","splitGenesByDirection","Set","gene","countSignificantProteins","runEnrichmentPipeline","organismCode","smartFilterEnabled","maxTermsPerSource","mapped","unmapped","geneNameCol","accToRows","acc","has","uniqueAccessions","keys","convertResults","accessions","gConvert","accToGene","incoming","geneArr","geneCol","GENE_SYMBOL","bgArray","directionDfs","upStats","downStats","upResults","filtered","downResults","enrichmentDf","append","totalInput","totalKept","totalDropped","showEnrichmentDialog","seededDisplay","organismInput","goBpInput","bool","goMfInput","goCcInput","keggInput","reactomeInput","wpInput","smartFilterInput","maxTermsInput","int","syncMaxTermsEnabled","enabled","totalFmt","selectedDisplay","code","selectedSources","pct","toFixed","setGroups","getGroups","setOrganism","getOrganism","showAnnotationDialog","intensityColNames","INTENSITY","startsWith","seed","available","runMetaSeed","persisted","getRunMeta","readRunMetaSeed","instrumentId","instrument_id","acquisitionDatetime","acquisition_datetime","availableSet","names","seedAnnotationDialogInputs","string","instrumentInput","tooltipText","datetimeInput","instrumentValue","trim","datetimeValue","isoDatetime","payload","runMeta","setRunMeta","applyAnnotation","randomNormal","u1","u2","imputeKnn","rawArrays","nCols","matrix","missing","Float64Array","miss","isNull","colMeans","rowsWithMissing","totalImputed","idx","distances","sumSq","sharedCount","dist","neighbors","showImputationDialog","log2ColNames","log2Cols","colsInput","downshiftInput","widthInput","minProbContainer","kInput","knnContainer","minValidInput","filterCountDiv","updateFilterCount","g1Cols","g2Cols","g1Valid","g2Valid","removed","selected","removeSet","trueCount","removeWhere","downshift","width","avg","imputeMean","imputeSd","imputeMinProb","imputeZero","med","imputeMedian","getIntensityOriginals","detectCurrentLog2Applied","originalNames","orig","l2","log2","showLog2ScaleDialog","originals","detection","alreadyLog2","hint","pipelineRan","changed","remove","tag","applyLog2Scale","medianNormalize","quantileNormalize","colData","indices","maxValid","rankMeans","lo","hi","globalPos","showNormalizationDialog","warningDiv","border","color","padding","margin","borderRadius","plotContainer","height","marginTop","updatePreview","innerHTML","longDf","boxPlot","valueColumnName","categoryColumnName","appendChild","rawColNames","endsWith","rawName","srcRaw","dst","src","dstRaw","vsnNormalize","RUNS_CSV_COLUMNS","SCHEMA_VERSION_KEY","opts","runsCsvPath","runsMetaPath","baselinePath","slugifyInstrumentId","csvEscape","indexOf","parseCsvRow","line","cell","serializeRow","run_id","run_label","median_intensity","missing_pct","control_corr","protein_count","rules_tripped","source_project_id","source_df_name","computed_at","deserializeRow","cells","rulesTripped","sourceProjectId","readRowsFromCsv","path","files","exists","parsed","text","lines","parseCsv","readAsText","readRunsMeta","upsertRun","input","findIndex","crypto","randomUUID","now","writeAsText","rowsToCsv","version","readSchemaVersion","meta","writeRunsMeta","writeSchemaVersion","loadRuns","localeCompare","loadBaseline","saveBaseline","baseline","meanSdValues","iterativeOutlierRemoval","maxIter","retained","excluded","trace","retained_run_ids","excluded_run_ids","iteration_trace","dropped","METRIC_KEYS","metricBaseline","computeBaselineStats","retainedRows","snapshot","runsToDataFrame","DATE_TIME","WHEELER_D4","isMissing","pearson","xs","ys","sumX","sumY","mx","my","dx2","dy2","dx","dy","denom","resolveCols","computeSpcMetrics","intensityCols","sampleCount","allValues","missingCells","totalCells","rowsWithData","rowHasData","medianIntensity","mid","missingPct","controlCorr","pairCount","ci","cj","sample_count","defaultRulesEnabledAllMetrics","nelson_1","nelson_2","nelson_3","nelson_4","nelson_5","nelson_6","nelson_7","nelson_8","RULE_FNS","ctx","tail","above","every","below","inc","dec","above2","below2","last3","last5","RULE_IDS","evaluateNelsonRules","baselineMean","baselineSd","metricLabel","id","classifyStatus","evaluateNelsonRulesAllMetrics","newMetrics","priorSeries","tripped","metricNames","newValue","trip","setSpcStatus","metrics","ruleResult","contains","ensureFreshStringColumn","LOCATION_KEYWORDS","LOCATION_COLORS","escapeRegex","findFirstLocation","lower","earliestMatch","earliestPos","category","keyword","RegExp","exec","parseSubcellularLocation","subcell","go","goText","location","ORGANISM_TAXONOMY","hsapiens","mmusculus","rnorvegicus","scerevisiae","ecoli","drerio","dmelanogaster","athaliana","celegans","STORE","SCHEMA_V","SCHEMA_KEY","VALID_CATEGORIES","chunk","runWithConcurrency","limit","work","nextIndex","workerCount","workers","all","getSubcellularLocations","progress","cache","userDataStorage","loadCache","resolved","misses","geneByAcc","fetched","taxClause","tax","taxonomyClause","flushCache","put","flushTimer","catch","accChunks","totalAcc","doneAcc","group","encodeURIComponent","locByAcc","reviewedByAcc","li","goc","reviewed","cat","mergeStreamTsv","loc","geneToUnknownAccs","geneChunks","totalGene","doneGene","_entryCache","fetchUniProtEntry","accession","PROTEIN_ID_HINTS","focusProtein","PROTEIN_ID","currentCell","windows","showContextPanel","wanted","attempt","document","querySelector","allExpanded","header","querySelectorAll","classList","click","expandUniProtPane","showGenericImportDialog","openFile","accept","open","file","reader","FileReader","onload","delimiter","fileName","suggestedProtein","suggestedGene","suggestedIntensityNames","proteinIdInput","STRING","geneNameInput","numericColNames","BIG_INT","intensityColsInput","initialDetection","log2Toggle","isLog2","previewContainer","createElement","selectedNames","proteinCol","intensityNames","mask","previewDf","grid","countLabel","updateLog2Detection","addTableView","showMappingDialog","createExpressionHeatmap","topN","labelColName","labelCol","adjPCol","indexedPValues","topNIndices","heatmapDf","allIntensityCols","zScoreColNames","colName","zColName","srcColOrig","origRaw","colMean","colStd","srcColClone","plot","gc","byIndex","visible","labelGc","group1ZCols","group2ZCols","clustered","dFunc","package","inputs","colNameList","distance","linkage","sortCol","props","isHeatmap","isGrid","title","setOptions","GROUP_COLORS","confidenceEllipse","xVals","yVals","nPoints","cx","cy","sxx","sxy","syy","disc","lambda1","lambda2","atan2","points","cosA","sinA","ex","ey","createPcaPlot","groupAssignment","pcaDf","varianceExplained","nComponents","nSamples","nProteins","proteinMeans","proteinCounts","Xt","aik","matmul","divisor","eigenvalues","eigenvectors","converged","maxVal","app","aqq","apq","aip","aiq","vip","viq","sortedEigenvalues","sortedEigenvectors","scores","pc1Pct","pc1Name","pc2Pct","pc2Name","pc2Col","groupNames","groupCol","computePCA","pc1ColName","pc2ColName","sp","scatter","labelColumnNames","displayLabels","pc1Col","groupName","ellipsePoints","region","area","fillColor","opacity","outlineColor","outlineWidth","annotationRegions","viewer","QC_COLUMNS","openQcDashboard","tv","maPlotOptions","xColumnName","yColumnName","markerDefaultSize","dirColName","_e","maPlot","addViewer","SCATTER_PLOT","maFormula","formulaLines","formula","addLine","maTrend","cvPlot","corrPlot","CORR_PLOT","xColumnNames","yColumnNames","missDf","missGrid","allowColSelection","barDf","missBar","barChart","splitColumnName","stackColumnName","dm","dockManager","protNode","dock","RIGHT","FILL","sampleNode","DOWN","activateTab","node","findNode","parent","container","setActiveChild","dateSlice","fieldRow","label","labelEl","fontWeight","fontSize","valueEl","marginBottom","DYNAMIC_SECTIONS","initProteomics","PackageFunctions","buildProteomicsTopMenu","importSpectronautCandidates","importSpectronaut","importMaxQuant","importFragPipe","importGenericMatrix","annotateExperiment","setLog2Scale","normalizeProteomics","imputeMissingValues","differentialExpression","computeSpcStatus","showVolcanoPlot","showHeatmap","showPcaPlot","showGroupMeanCorrelation","showQcDashboard","showSpcDashboard","showAllVisualizations","enrichmentAnalysis","exportEnrichmentInputs","enrichmentCharts","proteomicsDemo","proteomicsEnrichmentDemo","uniprotPanelWidget","shareAnalysisForReview","publishedAnalysisPanelWidget","recoverPublishedProjectsOnStartup","_package","requireSampleLevelData","action","decorator","propertyKey","descriptor","PRECURSOR_SIGNATURE_COLUMNS","sniffIsPrecursor","stream","pipeThrough","TextDecoderStream","getReader","maxBytes","read","cancel","activeFilterSubscriptions","autoDetectOrganism","dockComparisonFilterIfMultiContrast","cmpCol","found","distinct","displayNameCol","DISPLAY_NAME","sourceIdCol","SOURCE_ID","proteinIdCol","columnNames","filters","showBoolCombinedFilter","showHeader","showSearchBox","unsubscribe","savedBitSet","copyFrom","restoring","onFilterChanged","pipe","debounceTime","matched","selection","setAll","fireChanged","viewers","findVolcano","openCandidatesAnalysisView","volcanoErr","handlers","normalize","impute","WeakSet","ensure","view","TABLE_VIEW","dataFrame","ribbonMenu","sampleOnly","isEnabled","sampleLevelDisabledReason","imp","item","analyze","viz","buildProteomicsRibbonMenu","views","onViewAdded","onCurrentViewChanged","parseSpectronautText","priorRuns","priorRow","priorStatus","rules_enabled","volcanoOptions","spArg","metric","colorDim","hasPValue","initialMetric","metricInput","colorInput","labelTopNInput","axis","xMaxInput","xMax","yMaxInput","yMax","topNLabels","initialLabel","willFetchLocation","phase","detail","topNInput","volcano","heatmapPi","heatmap","pcaViewer","candidates","tables","analysisTv","adj","sig","best","bestP","topHitRow","runProteomicsDemo","setSem","sem","runEnrichmentDemo","allGroups","allUsersId","defaultGroupsIds","filteredGroups","hidden","personal","groupByName","friendlyName","groupItems","targetInput","groupInput","noteInput","textArea","verifyInput","banner","summary","priorVersion","updateBannerAndSummary","slug","dateStr","priorN","priorName","parsePriorVersionN","nextVersion","projectName","groupLabel","statusLabel","reviewerGroup","note","verify","project","showShareForReviewDialog","supersededBy","newerLink","newer","projects","backgroundColor","comparison","fcFold","fcLabel","pLabel","publishedAt","publishedBy","methodLabel","deMethod","sharerEmail","publishedByEmail","PUBLISHED_BY_EMAIL","readSharerEmail","mailtoUrl","sharerName","publishedDateStr","mailLink","href","mailRow","publishedAnalysisPanel","tryEvent","onProjectOpened","onCurrentProjectChanged","handleOpen","tags","autostartImmediate","description","demoPath","isDemoDashboard","panel","role","param","parseAccession","pipeMatch","upsMatch","bareMatch","findHostDataFrameForProtein","activeDf","uniprotPanel","fetchUniProtData","entry","link","proteinName","proteinDescription","recommendedName","fullName","submissionNames","getProteinName","genes","scientificName","funcComment","comments","commentType","funcText","texts","mf","bp","xref","uniProtKBCrossReferences","database","term","properties","extractGoTerms","goCategories","terms","goHeader","termText","termDiv","marginLeft","hostDf","perGroupHeader","bars","safeMax","H","hexRgb","argb","padStart","toUpperCase","COLORS","enrichedG1","enrichedG2","svgNs","svg","createElementNS","setAttribute","rect","notSig","whiskerX","BAR_W","yTop","yBot","txt","renderPerGroupBars","renderUniProtWidget","INTENSITY_SUFFIXES","PROTEIN_ID_COLUMNS","GENE_NAME_COLUMNS","CONTAMINANT_PREFIXES","findCol","matchIntensitySuffix","suffix","addPrimaryColumnFromVariants","sourceNames","newName","srcCol","parseFragPipeText","columnImportOptions","newlineIdx","buildIntensityColumnOptions","_i","prefix","filterContaminantRows","chosen","bucket","maxLfq","intensity","razor","pickQuantColumns","chosenQuant","assignSemanticTypes","INTENSITY_PREFIXES","FILTER_COLUMNS","filterByMarker","parseMaxQuantText","filterByIdPrefix","lowerName","processIntensityColumns","log2TransformColumns","nonFiniteCount","log2Name","log2Col","copyAsLog2Columns","addPrimaryColumnIfNeeded","sourceColName","hasSemicolon","newCol","detectLog2Status","inLog2Range","inRawRange","detectDelimiter","firstLine","autoSuggestProteinIdColumn","keywords","kw","autoSuggestGeneNameColumn","autoSuggestIntensityColumns","LOG2FC_COLUMNS","ADJ_P_COLUMNS","P_VALUE_COLUMNS","COMPARISON_COLUMNS","AVG_GROUP_QTY_NUM_COLUMNS","AVG_GROUP_QTY_DEN_COLUMNS","CONDITION_NUM_COLUMNS","CONDITION_DEN_COLUMNS","renameToCanonical","canonical","parseSpectronautCandidatesText","idColName","idCol2","canonG1","canonG2","anyFlip","fcCol","newFc","numCol","denCol","numRaw","denRaw","newNum","newDen","nv","dv","cmpVals","condNumCol","condDenCol","cnVals","cdVals","normalizeCandidatesSign","sigCol","adjPRaw","firstNonEmpty","cmp","REQUIRED_COLUMNS","QUANTITY_COLUMNS","tryParseRunDate","finalizeSpectronaut","proteins","proteinMap","organisms","orgValues","orgCol","sampleKey","sampleKeys","sampleMap","sampleFileNames","buildWideDataFrame","conditionMap","lastUnderscore","lastIndexOf","conditions","autoPopulateGroups","tryCastDouble","parseSpectronautStream","qValueThreshold","agg","headerParsed","colIdx","protI","condI","repI","qvalI","qtyI","fileI","orgI","runDateI","instrMethodI","expectedFields","earliestRunDateMs","earliestRunDateIso","firstInstrumentMethod","bytesRead","malformed","lastYield","performance","fileSize","handleFields","protein","qty","replicate","maxQuantity","minQvalue","og","rd","im","parseHeader","quantityColName","msg","sampleSet","aggToPivotResult","earliestRunDate","applySpcRunMetaSeed","condCol","replCol","protCol","ibaqCol","qvalCol","fileCol","runDateCol","instrMethodCol","qval","pivotSpectronaut","hasDate","hasInstr","FORMULA_LINE_ASSERTION_PREFIX","assertPublishedShape","contract","projId","closeAll","reopened","reDf","expectedName","expectedProjectName","expectedAllowlist","visibleCols","unexpected","expectedMeta","eqFloat","publishId","includesEnrichment","volcanoViewer","expectVolcano","expectFormulaLines","fcStr","pStr","minusLogPStr","log10","collected","dfLines","getOptions","lookLines","look","propLines","formulas","hasFcLine","hasPLine","PUBLISHED_FC_THRESHOLD","PUBLISHED_P_THRESHOLD","expectEnrichment","PUBLISHED_INCLUDES_ENRICHMENT","supersedes","got","SUPERSEDES","SUPERSEDED_BY","ENRICHMENT_WIRED_TAG","recoverPublishedProject","tableViews","findTableViewFor","parseFloat","hasFormulaLines","enrichDf","proteinDf","PUBLISHED","findPublishedEnrichmentSibling","addMetadataColumn","spec","constant","addNewDateTime","emptyForNull","applyVolcanoFormulaLines","yColName","yPrefix","fcPrefix","hLine","showViewerFormulaLines","publishAnalysis","user","email","optsAny","priorVersionN","parsePriorVersion","globalThis","generateUuid","enrichSource","frozen","adjPValue","required","allowlist","carryForwardTags","semTypeAssignments","includesEnrichmentStr","specs","PUBLISHED_AT","PUBLISHED_BY","PUBLISHED_TARGET","PUBLISHED_DE_METHOD","PUBLISHED_VERSION","PUBLISHED_ID","trimForPublish","frozenEnrich","intersection","directionCol","enrichClone","trimEnrichmentForPublish","umbrellaName","dapiAny","umbrella","spaces","createRootSpace","createErr","umbrellaClient","childName","childSpace","findChildByName","children","subspaceExists","addSubspace","subErr","childClient","addChild","getTableInfo","trimmedTv","viewInfo","getInfo","enrichViewInfo","enrichTv","uploadDataFrame","save","addEntity","mvErr","permissions","grant","grantErr","delete","rb","reviewerId","matchesGroup","projPerm","childSpacePerm","umbrellaPerm","inAny","perm","inView","inEdit","inShare","inDelete","healedOnce","assertErr","reopenedVolcano","fcFromTag","pFromTag","priorProjectId","priorReloaded","priorOptsErr","priorReopened","priorDf","supersededByCol","stampErr","restoredTv","readSetting","fallback","settings","reviewSpaceName","reviewNamePrefix","verifyPublishedDashboard","DE_COMPLETE_TAG","PUBLISHED_TAGS","META_COLUMNS","isPublished","getPublishedMetadata","readString","colKey","tagKey","readNumber","readDate","versionRaw","versionNum","setPublishedTags","slugifyTarget","findPriorShare","_group","namePrefix","versionRe","pickLatest","cands","bestV","namePattern","matching","buildMailtoUrl","subject","findColumn","nameHints","bySemType","hintLower","findProteomicsColumns","STORE_GENE_LABELS","SCHEMA_V_GENE_LABELS","PREDICTED_PREFIXES","isEnsemblEligible","isPredicted","extractReadableDescription","sentences","applyMarkerRules","improvedName","hadAsterisk","wasReclassified","pickBestName","rawId","external_name","display_name","resolveGeneLabels","displayArr","sourceArr","predicted","recordIfPredicted","dCol","sCol","ensIds","lookupResult","unresolvedAny","chunks","ids","post","retryAfter","waitMs","entries","safe","species","biotype","object_type","lookupEnsemblBatch","descCol","improved","cleaned","dRaw","finalName","rowsByName","duplicateRows","srcs","sid","unresolvedCount","ORGANISM_LIST","SCIENTIFIC_TO_CODE","scientific","organismDisplayForCode","organismCodeForDisplay","resolveOrganismCode","ORGANISM_COLUMN_HINTS","detectOrganismCode","findOrganismColumn","codes","SEMTYPE","SUBCELLULAR_LOCATION","NUMERATOR_MEAN","DENOMINATOR_MEAN","DEFAULT_FC_THRESHOLD","DEFAULT_P_THRESHOLD","DIRECTION_COLORS_BASE","activeSubscriptions","NEG_LOG10_FDR_COL","CHART_TOP_MARKER_COL","chartFilter","clauses","createEnrichmentDotPlot","scatterPlot","sizeColumnName","colorColumnName","markerMinSize","markerMaxSize","createEnrichmentBarChart","valueAggrType","barSortType","barSortOrder","orientation","wireEnrichmentToVolcano","EMPTY","geneToRows","onCurrentRowChanged","currentRowIdx","memberGenesStr","memberGenes","Boolean","hasDirection","dirCol","openEnrichmentVisualization","sub","dart","chartHost","parents","cap","dataset","smartFilterBanner","TOP","dockEnrichmentCharts","host","UNDERFLOW_NEGLOG10","MIN_VALUE","negLogCol","fdr","topMask","prepareEnrichmentChartColumns","upDotNode","downDotNode","dotNode","NUMERATOR_MEAN_COL","DENOMINATOR_MEAN_COL","DIAGONAL_FORMULA","ensureFreshFloat","groupMean","meanX","meanY","denX","denY","den","indexed","ranks","spearman","createGroupMeanCorrelation","numArr","denArr","m1","computeGroupMeans","showLabelsFor","rho","xName","yName","xCol","yCol","xRaw","yRaw","computePearsonSpearman","baseTitle","rStr","rhoStr","xColumnLabel","yColumnLabel","getIntensityColumns","computeMA","mArr","aArr","g1Mean","g2Mean","computeLoessTrend","windowFraction","aCol","mCol","mRaw","trendArr","halfWindow","computeCV","groupCols","cvColName","meanColName","cvArr","meanArr","delta","createMissingnessMatrix","fromInt32Array","unpivotIntensities","intensities","computeMissingBarData","sampleNames","missingPcts","g1Set","g2Set","nullCount","METRIC_LABELS","FORMULA_LINE_COLORS","LAST_INSTRUMENT_STORAGE_KEY","FALSE_ALARM_DISCLOSURE","disclosureKey","onIds","on","createSpcChartPanel","runsDf","iChart","lineChart","ucl","cl","lcl","computeControlLines","fl","mrColName","mrChart","mrCol","mrMean","mrUcl","flMr","ruleTooltip","rule","recomputeStatusesInPlace","statusCol","rulesCol","showDefineBaselineDialog","runs","onLocked","isRebuild","checkedSet","included_run_ids","runCheckboxes","listEl","maxHeight","overflowY","cb","run","iterateToggle","initialEnabled","ruleIds","ruleInputs","gridRows","disclosureEl","rid","currentEnabled","bodyEls","locked_at","dialog","el","checked","exclusionUnion","traceUnion","metricsSnapshot","openSpcDashboard","allRuns","instruments","lastPicked","last","baselineByInstrument","inst","itemToId","initialItem","picker","picked","mr","rc","prev","addMrColumns","refreshCharts","totalRuns","at","aggregateParetoCounts","ruleMetricCol","tripCountArr","totalRunsArr","pctArr","aggDf","chart","xLabel","yLabel","createParetoChart","empty","sidebar","onRebuildClick","onRuleToggle","heading","statusBlock","disclosure","checkbox","setDisclosure","buildSidebar","newBaseline","LEFT","sourceRaw","deps","projectsFind","resolveDrillDown","wireDrillDown","openDashboardForInstrument","NEG_LOG_COL","DIRECTION_COL","LOCATION_COL","VOLCANO_METRIC_TAG","activeVolcanoSubscriptions","VOLCANO_ROOT_CLASS","pickMetricColumn","ensureNegLog10Column","pCol","ensureDirectionColumn","g1Label","g2Label","nsLabel","colors","setCategorical","LOCATION_HASH_TAG","applyThresholdLines","yFormulaPrefix","fcFormulaPrefix","yAxisLabelForMetric","readVolcanoState","refreshVolcanoAxisLabel","showVolcanoBusy","hideVolcanoBusy","position","overlay","volcanoBusy","assign","top","transform","boxShadow","textAlign","pointerEvents","zIndex","maxWidth","labelDiv","detailDiv","updateVolcanoBusy","VOLCANO_LABEL_COL","VOLCANO_TOPN_TAG","VOLCANO_XMAX_TAG","VOLCANO_YMAX_TAG","getVolcanoAxisMax","setVolcanoAxisMax","write","applyVolcanoAxisBounds","xMin","yMin","getVolcanoTopN","applyTopNLabels","extraRows","findLabelSource","topNBySignificance","createVolcanoPlot","disposeVolcanoAttachments","colorColName","getElementById","head","ensureVolcanoStyles","synthesizeVolcanoTitle","volcanoAxisX","bottom","volcanoAxisY","transformOrigin","onPropertyValueChanged","attachAxisLabels","volcanoCounter","recompute","colorCol","perCategoryEnabled","categories","replaceChildren","onSelectionChanged","attachCounterOverlay","recomputeVolcano","dirName","accForRow","currentHash","charCodeAt","fnv1aHex","ensureLocationColumn","grok","rxjs","operators","ui","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","getter","definition","defineProperty","enumerable","prop","hasOwnProperty","Symbol","toStringTag","__webpack_exports__"],"sourceRoot":""}
|