@jax-data-science/sci-image-visualizer 0.17.0 → 0.18.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.
Files changed (121) hide show
  1. package/esm2022/lib/contracts/display-types.mjs +3 -2
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/geometry/cell-meshes.mjs +37 -0
  9. package/esm2022/lib/geometry/place.mjs +47 -0
  10. package/esm2022/lib/implementations/napari-js/napari-camera-depth.mjs +93 -0
  11. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
  12. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +2 -2
  13. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  14. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +81 -15
  15. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-cells.mjs +746 -0
  16. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +325 -18
  17. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +182 -24
  18. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +95 -5
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +15 -1
  20. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +30 -2
  21. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +40 -1
  22. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +111 -28
  23. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +14 -2
  24. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +180 -48
  25. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +28 -8
  26. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +2 -2
  27. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +10 -1
  28. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +30 -3
  29. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +15 -3
  30. package/esm2022/lib/region-editor/region-editor.component.mjs +24 -4
  31. package/esm2022/lib/region-source/region-source-ops.mjs +7 -1
  32. package/esm2022/lib/region-source/region-tiles.mjs +1 -1
  33. package/esm2022/lib/region-source/worker-region-source.mjs +24 -1
  34. package/esm2022/lib/routing-visualizer.service.mjs +404 -7
  35. package/esm2022/lib/spatial/observations-in-selection.mjs +83 -0
  36. package/esm2022/lib/spatial/plane-cells.mjs +119 -0
  37. package/esm2022/lib/spatial/spatial-controls.facade.mjs +298 -5
  38. package/esm2022/lib/spatial/spatial-encoding.mjs +35 -3
  39. package/esm2022/lib/spatial/spatial-hover.mjs +34 -1
  40. package/esm2022/lib/spatial/spatial-planes.mjs +49 -0
  41. package/esm2022/lib/spatial/spatial-selection.mjs +2 -2
  42. package/esm2022/lib/spatial/spatial-tile-merge.mjs +38 -1
  43. package/esm2022/lib/spatial/transcripts-in-selection.mjs +208 -0
  44. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +42 -65
  45. package/esm2022/lib/spatial-controls/spatial-color-by/spatial-color-by.component.mjs +187 -0
  46. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +47 -12
  47. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +3 -3
  48. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +38 -10
  49. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
  50. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
  51. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +79 -57
  52. package/esm2022/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.mjs +101 -0
  53. package/esm2022/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.mjs +94 -0
  54. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +9 -3
  55. package/esm2022/lib/store/region-source-scope.mjs +10 -1
  56. package/esm2022/lib/store/region-store.service.mjs +33 -2
  57. package/esm2022/lib/toolbar/toolbar.component.mjs +10 -3
  58. package/esm2022/lib/visualizer/spatial-region-set.mjs +95 -0
  59. package/esm2022/lib/visualizer.component.mjs +40 -4
  60. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs} +4521 -759
  61. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-CBiLcnE6.mjs.map +1 -0
  62. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-BXHjv4PE.mjs} +2 -2
  63. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-BXHjv4PE.mjs.map} +1 -1
  64. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
  65. package/fesm2022/region-source.worker.js +84 -2
  66. package/lib/contracts/display-types.d.ts +90 -4
  67. package/lib/contracts/image.contract.d.ts +6 -0
  68. package/lib/contracts/ports/spatial-data.port.d.ts +7 -0
  69. package/lib/contracts/region-editor-api.contract.d.ts +9 -0
  70. package/lib/contracts/region-store.contract.d.ts +6 -0
  71. package/lib/contracts/spatial-dataset.contract.d.ts +7 -1
  72. package/lib/contracts/visualizer.contract.d.ts +43 -1
  73. package/lib/geometry/cell-meshes.d.ts +27 -0
  74. package/lib/geometry/place.d.ts +45 -0
  75. package/lib/implementations/napari-js/napari-camera-depth.d.ts +23 -0
  76. package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
  77. package/lib/implementations/napari-js/napari-scene.d.ts +12 -0
  78. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +19 -3
  79. package/lib/implementations/napari-js/napari-spatial-3d-cells.d.ts +141 -0
  80. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +87 -0
  81. package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +49 -8
  82. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +22 -0
  83. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +12 -0
  84. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +15 -0
  85. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +27 -1
  86. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +38 -19
  87. package/lib/implementations/napari-js/napari-volume-scene.d.ts +2 -0
  88. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +53 -0
  89. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +11 -2
  90. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +7 -0
  91. package/lib/region-editor/class-tree/class-tree.component.d.ts +16 -1
  92. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +10 -1
  93. package/lib/region-editor/region-editor.component.d.ts +4 -0
  94. package/lib/region-source/region-source-ops.d.ts +12 -0
  95. package/lib/region-source/region-tiles.d.ts +8 -0
  96. package/lib/region-source/worker-region-source.d.ts +18 -0
  97. package/lib/routing-visualizer.service.d.ts +140 -1
  98. package/lib/spatial/observations-in-selection.d.ts +43 -0
  99. package/lib/spatial/plane-cells.d.ts +37 -0
  100. package/lib/spatial/spatial-controls.facade.d.ts +59 -0
  101. package/lib/spatial/spatial-encoding.d.ts +14 -1
  102. package/lib/spatial/spatial-hover.d.ts +23 -0
  103. package/lib/spatial/spatial-planes.d.ts +22 -0
  104. package/lib/spatial/spatial-selection.d.ts +2 -1
  105. package/lib/spatial/spatial-tile-merge.d.ts +9 -0
  106. package/lib/spatial/transcripts-in-selection.d.ts +95 -0
  107. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +19 -28
  108. package/lib/spatial-controls/spatial-color-by/spatial-color-by.component.d.ts +64 -0
  109. package/lib/spatial-controls/spatial-controls.component.d.ts +17 -2
  110. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +16 -6
  111. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +26 -23
  112. package/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.d.ts +48 -0
  113. package/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.d.ts +43 -0
  114. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +3 -1
  115. package/lib/store/region-source-scope.d.ts +4 -0
  116. package/lib/store/region-store.service.d.ts +21 -0
  117. package/lib/toolbar/toolbar.component.d.ts +6 -1
  118. package/lib/visualizer/spatial-region-set.d.ts +55 -0
  119. package/lib/visualizer.component.d.ts +14 -0
  120. package/package.json +1 -1
  121. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs.map +0 -1
@@ -0,0 +1,101 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, NgZone, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ButtonModule } from 'primeng/button';
4
+ import { TooltipModule } from 'primeng/tooltip';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@angular/common";
7
+ import * as i2 from "primeng/button";
8
+ import * as i3 from "primeng/tooltip";
9
+ /**
10
+ * "Observations in selection", in the Observations section: the observations of what is selected —
11
+ * a cell, a cell type picked on the canvas, the selected regions — by the grouping they are coloured
12
+ * by (else the cell types), with a few measurements' means, or one cell's id, groupings and values.
13
+ * Every observation in spatial 3D; in 2D those on the plane shown. See
14
+ * `ISpatialControls.getObservationsInSelection$`.
15
+ *
16
+ * Collapsible; followed only while expanded (and while the Observations section, which holds it, is
17
+ * open).
18
+ */
19
+ export class SpatialSelectionObservationsComponent {
20
+ constructor(zone, cdr) {
21
+ this.zone = zone;
22
+ this.cdr = cdr;
23
+ /** The spatial controls the list is read through; null without a `SPATIAL_DATA_PORT`. */
24
+ this.controls = null;
25
+ /** In spatial 3D: the list is of the whole volume. */
26
+ this.is3d = false;
27
+ /** Expanded: the list is followed and shown. */
28
+ this.expanded = true;
29
+ /** The selection's observations (null until the first answer). */
30
+ this.list = null;
31
+ this.sub = null;
32
+ }
33
+ ngOnChanges(changes) {
34
+ if (changes['controls'])
35
+ this.watch();
36
+ }
37
+ ngOnDestroy() {
38
+ this.sub?.unsubscribe();
39
+ this.sub = null;
40
+ }
41
+ /** Whether there is a list to offer. */
42
+ get available() {
43
+ return !!this.controls?.getObservationsInSelection$;
44
+ }
45
+ /** The largest group, for the bars. */
46
+ get max() {
47
+ return this.list?.groups?.[0]?.count ?? 0;
48
+ }
49
+ toggle() {
50
+ this.expanded = !this.expanded;
51
+ this.watch();
52
+ }
53
+ watch() {
54
+ this.sub?.unsubscribe();
55
+ this.sub = null;
56
+ if (!this.expanded)
57
+ return;
58
+ const list$ = this.controls?.getObservationsInSelection$?.();
59
+ if (!list$)
60
+ return;
61
+ this.sub = list$.subscribe((state) => this.zone.run(() => {
62
+ // Keep the last list on screen while the next one loads, so it does not flicker.
63
+ this.list =
64
+ state.state === 'loading' && this.list?.state === 'ready'
65
+ ? { ...this.list, state: 'loading', label: state.label ?? this.list.label }
66
+ : state;
67
+ this.cdr.markForCheck();
68
+ }));
69
+ }
70
+ /** A measurement as shown: a number to 3 significant figures (with its unit), text as it is. */
71
+ format(m) {
72
+ if (typeof m.value === 'string')
73
+ return m.value;
74
+ const v = m.value;
75
+ const text = Math.abs(v) >= 1000 ? Math.round(v).toLocaleString() : Number(v.toPrecision(3)).toString();
76
+ return m.unit ? `${text} ${m.unit}` : text;
77
+ }
78
+ /** The groups as tab-separated text (group, observations), for a spreadsheet. */
79
+ copy() {
80
+ const groups = this.list?.groups;
81
+ if (!groups?.length)
82
+ return;
83
+ const head = this.list?.groupColumn ?? 'group';
84
+ const text = [`${head}\tobservations`, ...groups.map((g) => `${g.name}\t${g.count}`)].join('\n');
85
+ void navigator.clipboard?.writeText(text).catch(() => undefined);
86
+ }
87
+ trackGroup(_i, g) {
88
+ return g.name;
89
+ }
90
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialSelectionObservationsComponent, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
91
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialSelectionObservationsComponent, isStandalone: true, selector: "spatial-selection-observations", inputs: { controls: "controls", is3d: "is3d" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"available\">\n <button type=\"button\" class=\"sc-seltx-toggle sc-subhead\" [attr.aria-expanded]=\"expanded\" (click)=\"toggle()\">\n <i class=\"pi\" [class.pi-chevron-down]=\"expanded\" [class.pi-chevron-right]=\"!expanded\"></i>\n Observations in selection\n </button>\n <div class=\"sc-seltx\" *ngIf=\"expanded\">\n <ng-container *ngIf=\"list; else waiting\">\n <div class=\"sc-seltx-head\" *ngIf=\"list.label\">\n <span class=\"sc-seltx-label\" [title]=\"list.label\">{{ list.label }}</span>\n <small class=\"sc-hint\" *ngIf=\"list.plane\">\n plane {{ list.plane.index + 1 }} of {{ list.plane.count }}\n </small>\n <small class=\"sc-hint\" *ngIf=\"!list.plane && is3d\">whole volume</small>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'empty'\">{{ list.message }}</small>\n <small class=\"sc-hint sc-error\" *ngIf=\"list.state === 'error'\">{{ list.message }}</small>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'loading'\">\n <i class=\"pi pi-spin pi-spinner\"></i> Listing observations\u2026\n </small>\n <ng-container *ngIf=\"list.total !== undefined && list.state !== 'empty' && list.state !== 'error'\">\n <div class=\"sc-seltx-summary\">\n <span>\n <b>{{ list.total | number }}</b> {{ list.total === 1 ? 'observation' : 'observations' }}\n <ng-container *ngIf=\"list.groupColumn && list.groups?.length\"\n >\u00B7 {{ list.groups!.length | number }} {{ list.groups!.length === 1 ? 'group' : 'groups' }} of\n {{ list.groupColumn }}</ng-container\n >\n </span>\n <p-button\n *ngIf=\"list.groups?.length\"\n icon=\"pi pi-copy\"\n size=\"small\"\n [text]=\"true\"\n pTooltip=\"Copy the groups (group, observations) as tab-separated text\"\n tooltipPosition=\"top\"\n (onClick)=\"copy()\"\n ></p-button>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.total === 0\">No observations in the selection.</small>\n <div class=\"sc-seltx-head\" *ngIf=\"list.cellId\">\n <span class=\"sc-hint\">Cell id</span>\n <span class=\"sc-seltx-label\" [title]=\"list.cellId\">{{ list.cellId }}</span>\n </div>\n <ol class=\"sc-seltx-list\" *ngIf=\"list.groups?.length\" [class.stale]=\"list.state === 'loading'\">\n <li *ngFor=\"let g of list.groups; trackBy: trackGroup\">\n <span class=\"sc-seltx-gene\" [title]=\"g.name\"\n ><span class=\"sc-seltx-swatch\" [style.background]=\"g.color\"></span>{{ g.name }}</span\n >\n <span class=\"sc-seltx-bar\"\n ><span [style.width.%]=\"(100 * g.count) / (max || 1)\" [style.background]=\"g.color\"></span\n ></span>\n <span class=\"sc-seltx-count\">{{ g.count | number }}</span>\n </li>\n </ol>\n <dl class=\"sc-seltx-measures\" *ngIf=\"list.measures?.length\" [class.stale]=\"list.state === 'loading'\">\n <ng-container *ngFor=\"let m of list.measures\">\n <dt [title]=\"m.name\">{{ m.mean ? 'Mean ' + m.name : m.name }}</dt>\n <dd>{{ format(m) }}</dd>\n </ng-container>\n </dl>\n </ng-container>\n </ng-container>\n <ng-template #waiting>\n <small class=\"sc-hint\"><i class=\"pi pi-spin pi-spinner\"></i> Listing observations\u2026</small>\n </ng-template>\n </div>\n</ng-container>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}.sc-subsection{display:flex;flex-direction:column;gap:.45rem}.sc-subsection-head{cursor:pointer;-webkit-user-select:none;user-select:none}.sc-subsection-head i{font-size:.65rem}.sc-subsection-head:hover .sc-subsection-title{color:var(--primary-color, #3b82f6)}.sc-subsection-body{display:flex;flex-direction:column;gap:.45rem;padding-left:.6rem;border-left:2px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}.sc-seltx-toggle{width:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;text-align:left}.sc-seltx-toggle i{font-size:.65rem}.sc-seltx-toggle:hover{color:var(--primary-color, #3b82f6)}.sc-seltx{display:flex;flex-direction:column;gap:.35rem}.sc-seltx-head{display:flex;align-items:baseline;gap:.5rem;min-width:0}.sc-seltx-label{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-summary{display:flex;align-items:center;justify-content:space-between;font-size:.78rem}.sc-seltx-list{list-style:none;margin:0;padding:0;max-height:16rem;overflow-y:auto;font-size:.78rem}.sc-seltx-list.stale{opacity:.55}.sc-seltx-list li{display:grid;grid-template-columns:minmax(4rem,7rem) 1fr auto;align-items:center;gap:.5rem;padding:.1rem 0}.sc-seltx-gene{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-bar{height:.45rem;border-radius:2px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-seltx-bar span{display:block;height:100%;background:var(--primary-color, #3b82f6)}.sc-seltx-count{font-variant-numeric:tabular-nums;text-align:right;min-width:3rem}.sc-seltx-swatch{display:inline-block;width:.6rem;height:.6rem;margin-right:.35rem;border-radius:2px;vertical-align:baseline}.sc-seltx-measures{display:grid;grid-template-columns:minmax(4rem,1fr) auto;gap:.1rem .75rem;margin:0;font-size:.78rem}.sc-seltx-measures dt{color:var(--text-color-secondary, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-measures dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
92
+ }
93
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialSelectionObservationsComponent, decorators: [{
94
+ type: Component,
95
+ args: [{ selector: 'spatial-selection-observations', standalone: true, imports: [CommonModule, ButtonModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"available\">\n <button type=\"button\" class=\"sc-seltx-toggle sc-subhead\" [attr.aria-expanded]=\"expanded\" (click)=\"toggle()\">\n <i class=\"pi\" [class.pi-chevron-down]=\"expanded\" [class.pi-chevron-right]=\"!expanded\"></i>\n Observations in selection\n </button>\n <div class=\"sc-seltx\" *ngIf=\"expanded\">\n <ng-container *ngIf=\"list; else waiting\">\n <div class=\"sc-seltx-head\" *ngIf=\"list.label\">\n <span class=\"sc-seltx-label\" [title]=\"list.label\">{{ list.label }}</span>\n <small class=\"sc-hint\" *ngIf=\"list.plane\">\n plane {{ list.plane.index + 1 }} of {{ list.plane.count }}\n </small>\n <small class=\"sc-hint\" *ngIf=\"!list.plane && is3d\">whole volume</small>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'empty'\">{{ list.message }}</small>\n <small class=\"sc-hint sc-error\" *ngIf=\"list.state === 'error'\">{{ list.message }}</small>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'loading'\">\n <i class=\"pi pi-spin pi-spinner\"></i> Listing observations\u2026\n </small>\n <ng-container *ngIf=\"list.total !== undefined && list.state !== 'empty' && list.state !== 'error'\">\n <div class=\"sc-seltx-summary\">\n <span>\n <b>{{ list.total | number }}</b> {{ list.total === 1 ? 'observation' : 'observations' }}\n <ng-container *ngIf=\"list.groupColumn && list.groups?.length\"\n >\u00B7 {{ list.groups!.length | number }} {{ list.groups!.length === 1 ? 'group' : 'groups' }} of\n {{ list.groupColumn }}</ng-container\n >\n </span>\n <p-button\n *ngIf=\"list.groups?.length\"\n icon=\"pi pi-copy\"\n size=\"small\"\n [text]=\"true\"\n pTooltip=\"Copy the groups (group, observations) as tab-separated text\"\n tooltipPosition=\"top\"\n (onClick)=\"copy()\"\n ></p-button>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.total === 0\">No observations in the selection.</small>\n <div class=\"sc-seltx-head\" *ngIf=\"list.cellId\">\n <span class=\"sc-hint\">Cell id</span>\n <span class=\"sc-seltx-label\" [title]=\"list.cellId\">{{ list.cellId }}</span>\n </div>\n <ol class=\"sc-seltx-list\" *ngIf=\"list.groups?.length\" [class.stale]=\"list.state === 'loading'\">\n <li *ngFor=\"let g of list.groups; trackBy: trackGroup\">\n <span class=\"sc-seltx-gene\" [title]=\"g.name\"\n ><span class=\"sc-seltx-swatch\" [style.background]=\"g.color\"></span>{{ g.name }}</span\n >\n <span class=\"sc-seltx-bar\"\n ><span [style.width.%]=\"(100 * g.count) / (max || 1)\" [style.background]=\"g.color\"></span\n ></span>\n <span class=\"sc-seltx-count\">{{ g.count | number }}</span>\n </li>\n </ol>\n <dl class=\"sc-seltx-measures\" *ngIf=\"list.measures?.length\" [class.stale]=\"list.state === 'loading'\">\n <ng-container *ngFor=\"let m of list.measures\">\n <dt [title]=\"m.name\">{{ m.mean ? 'Mean ' + m.name : m.name }}</dt>\n <dd>{{ format(m) }}</dd>\n </ng-container>\n </dl>\n </ng-container>\n </ng-container>\n <ng-template #waiting>\n <small class=\"sc-hint\"><i class=\"pi pi-spin pi-spinner\"></i> Listing observations\u2026</small>\n </ng-template>\n </div>\n</ng-container>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}.sc-subsection{display:flex;flex-direction:column;gap:.45rem}.sc-subsection-head{cursor:pointer;-webkit-user-select:none;user-select:none}.sc-subsection-head i{font-size:.65rem}.sc-subsection-head:hover .sc-subsection-title{color:var(--primary-color, #3b82f6)}.sc-subsection-body{display:flex;flex-direction:column;gap:.45rem;padding-left:.6rem;border-left:2px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}.sc-seltx-toggle{width:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;text-align:left}.sc-seltx-toggle i{font-size:.65rem}.sc-seltx-toggle:hover{color:var(--primary-color, #3b82f6)}.sc-seltx{display:flex;flex-direction:column;gap:.35rem}.sc-seltx-head{display:flex;align-items:baseline;gap:.5rem;min-width:0}.sc-seltx-label{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-summary{display:flex;align-items:center;justify-content:space-between;font-size:.78rem}.sc-seltx-list{list-style:none;margin:0;padding:0;max-height:16rem;overflow-y:auto;font-size:.78rem}.sc-seltx-list.stale{opacity:.55}.sc-seltx-list li{display:grid;grid-template-columns:minmax(4rem,7rem) 1fr auto;align-items:center;gap:.5rem;padding:.1rem 0}.sc-seltx-gene{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-bar{height:.45rem;border-radius:2px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-seltx-bar span{display:block;height:100%;background:var(--primary-color, #3b82f6)}.sc-seltx-count{font-variant-numeric:tabular-nums;text-align:right;min-width:3rem}.sc-seltx-swatch{display:inline-block;width:.6rem;height:.6rem;margin-right:.35rem;border-radius:2px;vertical-align:baseline}.sc-seltx-measures{display:grid;grid-template-columns:minmax(4rem,1fr) auto;gap:.1rem .75rem;margin:0;font-size:.78rem}.sc-seltx-measures dt{color:var(--text-color-secondary, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-measures dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}:host{display:contents}\n"] }]
96
+ }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { controls: [{
97
+ type: Input
98
+ }], is3d: [{
99
+ type: Input
100
+ }] } });
101
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1zZWxlY3Rpb24tb2JzZXJ2YXRpb25zLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLXNlbGVjdGlvbi1vYnNlcnZhdGlvbnMvc3BhdGlhbC1zZWxlY3Rpb24tb2JzZXJ2YXRpb25zLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLXNlbGVjdGlvbi1vYnNlcnZhdGlvbnMvc3BhdGlhbC1zZWxlY3Rpb24tb2JzZXJ2YXRpb25zLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxLQUFLLEVBQ0wsTUFBTSxHQUlQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDOzs7OztBQU1oRDs7Ozs7Ozs7O0dBU0c7QUFTSCxNQUFNLE9BQU8scUNBQXFDO0lBWWhELFlBQ21CLElBQVksRUFDWixHQUFzQjtRQUR0QixTQUFJLEdBQUosSUFBSSxDQUFRO1FBQ1osUUFBRyxHQUFILEdBQUcsQ0FBbUI7UUFiekMseUZBQXlGO1FBQ2hGLGFBQVEsR0FBNEIsSUFBSSxDQUFDO1FBQ2xELHNEQUFzRDtRQUM3QyxTQUFJLEdBQUcsS0FBSyxDQUFDO1FBRXRCLGdEQUFnRDtRQUN0QyxhQUFRLEdBQUcsSUFBSSxDQUFDO1FBQzFCLGtFQUFrRTtRQUN4RCxTQUFJLEdBQW1DLElBQUksQ0FBQztRQUM5QyxRQUFHLEdBQXdCLElBQUksQ0FBQztJQUtyQyxDQUFDO0lBRUosV0FBVyxD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QUFNLElBQUksR0FBRyxDQUFDLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNqRyxLQUFLLFNBQVMsQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRVMsVUFBVSxDQUFDLEVBQVUsRUFBRSxDQUFtQjtRQUNsRCxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDaEIsQ0FBQzs4R0E5RVUscUNBQXFDO2tHQUFyQyxxQ0FBcUMsK0pDcENsRCwrK0dBbUVBLDR0TkRwQ1ksWUFBWSx1VEFBRSxZQUFZLDZYQUFFLGFBQWE7OzJGQUt4QyxxQ0FBcUM7a0JBUmpELFNBQVM7K0JBQ0UsZ0NBQWdDLGNBQzlCLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxZQUFZLEVBQUUsYUFBYSxDQUFDLG1CQUduQyx1QkFBdUIsQ0FBQyxNQUFNOzJHQUl0QyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBJbnB1dCxcbiAgTmdab25lLFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9idXR0b24nO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHR5cGUgeyBJU3BhdGlhbENvbnRyb2xzIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHR5cGUgeyBPYnNlcnZhdGlvbnNJblNlbGVjdGlvbiB9IGZyb20gJy4uLy4uL2NvbnRyYWN0cy9kaXNwbGF5LXR5cGVzJztcblxuLyoqXG4gKiBcIk9ic2VydmF0aW9ucyBpbiBzZWxlY3Rpb25cIiwgaW4gdGhlIE9ic2VydmF0aW9ucyBzZWN0aW9uOiB0aGUgb2JzZXJ2YXRpb25zIG9mIHdoYXQgaXMgc2VsZWN0ZWQg4oCUXG4gKiBhIGNlbGwsIGEgY2VsbCB0eXBlIHBpY2tlZCBvbiB0aGUgY2FudmFzLCB0aGUgc2VsZWN0ZWQgcmVnaW9ucyDigJQgYnkgdGhlIGdyb3VwaW5nIHRoZXkgYXJlIGNvbG91cmVkXG4gKiBieSAoZWxzZSB0aGUgY2VsbCB0eXBlcyksIHdpdGggYSBmZXcgbWVhc3VyZW1lbnRzJyBtZWFucywgb3Igb25lIGNlbGwncyBpZCwgZ3JvdXBpbmdzIGFuZCB2YWx1ZXMuXG4gKiBFdmVyeSBvYnNlcnZhdGlvbiBpbiBzcGF0aWFsIDNEOyBpbiAyRCB0aG9zZSBvbiB0aGUgcGxhbmUgc2hvd24uIFNlZVxuICogYElTcGF0aWFsQ29udHJvbHMuZ2V0T2JzZXJ2YXRpb25zSW5TZWxlY3Rpb24kYC5cbiAqXG4gKiBDb2xsYXBzaWJsZTsgZm9sbG93ZWQgb25seSB3aGlsZSBleHBhbmRlZCAoYW5kIHdoaWxlIHRoZSBPYnNlcnZhdGlvbnMgc2VjdGlvbiwgd2hpY2ggaG9sZHMgaXQsIGlzXG4gKiBvcGVuKS5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnc3BhdGlhbC1zZWxlY3Rpb24tb2JzZXJ2YXRpb25zJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgQnV0dG9uTW9kdWxlLCBUb29sdGlwTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL3NwYXRpYWwtc2VsZWN0aW9uLW9ic2VydmF0aW9ucy5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NwYXRpYWwtc2VsZWN0aW9uLW9ic2VydmF0aW9ucy5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU3BhdGlhbFNlbGVjdGlvbk9ic2VydmF0aW9uc0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgLyoqIFRoZSBzcGF0aWFsIGNvbnRyb2xzIHRoZSBsaXN0IGlzIHJlYWQgdGhyb3VnaDsgbnVsbCB3aXRob3V0IGEgYFNQQVRJQUxfREFUQV9QT1JUYC4gKi9cbiAgQElucHV0KCkgY29udHJvbHM6IElTcGF0aWFsQ29udHJvbHMgfCBudWxsID0gbnVsbDtcbiAgLyoqIEluIHNwYXRpYWwgM0Q6IHRoZSBsaXN0IGlzIG9mIHRoZSB3aG9sZSB2b2x1bWUuICovXG4gIEBJbnB1dCgpIGlzM2QgPSBmYWxzZTtcblxuICAvKiogRXhwYW5kZWQ6IHRoZSBsaXN0IGlzIGZvbGxvd2VkIGFuZCBzaG93bi4gKi9cbiAgcHJvdGVjdGVkIGV4cGFuZGVkID0gdHJ1ZTtcbiAgLyoqIFRoZSBzZWxlY3Rpb24ncyBvYnNlcnZhdGlvbnMgKG51bGwgdW50aWwgdGhlIGZpcnN0IGFuc3dlcikuICovXG4gIHByb3RlY3RlZCBsaXN0OiBPYnNlcnZhdGlvbnNJblNlbGVjdGlvbiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHN1YjogU3Vic2NyaXB0aW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSB6b25lOiBOZ1pvbmUsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZHI6IENoYW5nZURldGVjdG9yUmVmLFxuICApIHt9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGlmIChjaGFuZ2VzWydjb250cm9scyddKSB0aGlzLndhdGNoKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN1Yj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnN1YiA9IG51bGw7XG4gIH1cblxuICAvKiogV2hldGhlciB0aGVyZSBpcyBhIGxpc3QgdG8gb2ZmZXIuICovXG4gIHByb3RlY3RlZCBnZXQgYXZhaWxhYmxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMuY29udHJvbHM/LmdldE9ic2VydmF0aW9uc0luU2VsZWN0aW9uJDtcbiAgfVxuXG4gIC8qKiBUaGUgbGFyZ2VzdCBncm91cCwgZm9yIHRoZSBiYXJzLiAqL1xuICBwcm90ZWN0ZWQgZ2V0IG1heCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmxpc3Q/Lmdyb3Vwcz8uWzBdPy5jb3VudCA/PyAwO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRvZ2dsZSgpOiB2b2lkIHtcbiAgICB0aGlzLmV4cGFuZGVkID0gIXRoaXMuZXhwYW5kZWQ7XG4gICAgdGhpcy53YXRjaCgpO1xuICB9XG5cbiAgcHJpdmF0ZSB3YXRjaCgpOiB2b2lkIHtcbiAgICB0aGlzLnN1Yj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnN1YiA9IG51bGw7XG4gICAgaWYgKCF0aGlzLmV4cGFuZGVkKSByZXR1cm47XG4gICAgY29uc3QgbGlzdCQgPSB0aGlzLmNvbnRyb2xzPy5nZXRPYnNlcnZhdGlvbnNJblNlbGVjdGlvbiQ/LigpO1xuICAgIGlmICghbGlzdCQpIHJldHVybjtcbiAgICB0aGlzLnN1YiA9IGxpc3QkLnN1YnNjcmliZSgoc3RhdGUpID0+XG4gICAgICB0aGlzLnpvbmUucnVuKCgpID0+IHtcbiAgICAgICAgLy8gS2VlcCB0aGUgbGFzdCBsaXN0IG9uIHNjcmVlbiB3aGlsZSB0aGUgbmV4dCBvbmUgbG9hZHMsIHNvIGl0IGRvZXMgbm90IGZsaWNrZXIuXG4gICAgICAgIHRoaXMubGlzdCA9XG4gICAgICAgICAgc3RhdGUuc3RhdGUgPT09ICdsb2FkaW5nJyAmJiB0aGlzLmxpc3Q/LnN0YXRlID09PSAncmVhZHknXG4gICAgICAgICAgICA/IHsgLi4udGhpcy5saXN0LCBzdGF0ZTogJ2xvYWRpbmcnLCBsYWJlbDogc3RhdGUubGFiZWwgPz8gdGhpcy5saXN0LmxhYmVsIH1cbiAgICAgICAgICAgIDogc3RhdGU7XG4gICAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBBIG1lYXN1cmVtZW50IGFzIHNob3duOiBhIG51bWJlciB0byAzIHNpZ25pZmljYW50IGZpZ3VyZXMgKHdpdGggaXRzIHVuaXQpLCB0ZXh0IGFzIGl0IGlzLiAqL1xuICBwcm90ZWN0ZWQgZm9ybWF0KG06IHsgdmFsdWU6IHN0cmluZyB8IG51bWJlcjsgdW5pdD86IHN0cmluZyB9KTogc3RyaW5nIHtcbiAgICBpZiAodHlwZW9mIG0udmFsdWUgPT09ICdzdHJpbmcnKSByZXR1cm4gbS52YWx1ZTtcbiAgICBjb25zdCB2ID0gbS52YWx1ZTtcbiAgICBjb25zdCB0ZXh0ID0gTWF0aC5hYnModikgPj0gMTAwMCA/IE1hdGgucm91bmQodikudG9Mb2NhbGVTdHJpbmcoKSA6IE51bWJlcih2LnRvUHJlY2lzaW9uKDMpKS50b1N0cmluZygpO1xuICAgIHJldHVybiBtLnVuaXQgPyBgJHt0ZXh0fSAke20udW5pdH1gIDogdGV4dDtcbiAgfVxuXG4gIC8qKiBUaGUgZ3JvdXBzIGFzIHRhYi1zZXBhcmF0ZWQgdGV4dCAoZ3JvdXAsIG9ic2VydmF0aW9ucyksIGZvciBhIHNwcmVhZHNoZWV0LiAqL1xuICBwcm90ZWN0ZWQgY29weSgpOiB2b2lkIHtcbiAgICBjb25zdCBncm91cHMgPSB0aGlzLmxpc3Q/Lmdyb3VwcztcbiAgICBpZiAoIWdyb3Vwcz8ubGVuZ3RoKSByZXR1cm47XG4gICAgY29uc3QgaGVhZCA9IHRoaXMubGlzdD8uZ3JvdXBDb2x1bW4gPz8gJ2dyb3VwJztcbiAgICBjb25zdCB0ZXh0ID0gW2Ake2hlYWR9XFx0b2JzZXJ2YXRpb25zYCwgLi4uZ3JvdXBzLm1hcCgoZykgPT4gYCR7Zy5uYW1lfVxcdCR7Zy5jb3VudH1gKV0uam9pbignXFxuJyk7XG4gICAgdm9pZCBuYXZpZ2F0b3IuY2xpcGJvYXJkPy53cml0ZVRleHQodGV4dCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgfVxuXG4gIHByb3RlY3RlZCB0cmFja0dyb3VwKF9pOiBudW1iZXIsIGc6IHsgbmFtZTogc3RyaW5nIH0pOiBzdHJpbmcge1xuICAgIHJldHVybiBnLm5hbWU7XG4gIH1cbn1cbiIsIjxuZy1jb250YWluZXIgKm5nSWY9XCJhdmFpbGFibGVcIj5cbiAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJzYy1zZWx0eC10b2dnbGUgc2Mtc3ViaGVhZFwiIFthdHRyLmFyaWEtZXhwYW5kZWRdPVwiZXhwYW5kZWRcIiAoY2xpY2spPVwidG9nZ2xlKClcIj5cbiAgICA8aSBjbGFzcz1cInBpXCIgW2NsYXNzLnBpLWNoZXZyb24tZG93bl09XCJleHBhbmRlZFwiIFtjbGFzcy5waS1jaGV2cm9uLXJpZ2h0XT1cIiFleHBhbmRlZFwiPjwvaT5cbiAgICBPYnNlcnZhdGlvbnMgaW4gc2VsZWN0aW9uXG4gIDwvYnV0dG9uPlxuICA8ZGl2IGNsYXNzPVwic2Mtc2VsdHhcIiAqbmdJZj1cImV4cGFuZGVkXCI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpc3Q7IGVsc2Ugd2FpdGluZ1wiPlxuICAgICAgPGRpdiBjbGFzcz1cInNjLXNlbHR4LWhlYWRcIiAqbmdJZj1cImxpc3QubGFiZWxcIj5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1zZWx0eC1sYWJlbFwiIFt0aXRsZV09XCJsaXN0LmxhYmVsXCI+e3sgbGlzdC5sYWJlbCB9fTwvc3Bhbj5cbiAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwibGlzdC5wbGFuZVwiPlxuICAgICAgICAgIHBsYW5lIHt7IGxpc3QucGxhbmUuaW5kZXggKyAxIH19IG9mIHt7IGxpc3QucGxhbmUuY291bnQgfX1cbiAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwiIWxpc3QucGxhbmUgJiYgaXMzZFwiPndob2xlIHZvbHVtZTwvc21hbGw+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cImxpc3Quc3RhdGUgPT09ICdlbXB0eSdcIj57eyBsaXN0Lm1lc3NhZ2UgfX08L3NtYWxsPlxuICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludCBzYy1lcnJvclwiICpuZ0lmPVwibGlzdC5zdGF0ZSA9PT0gJ2Vycm9yJ1wiPnt7IGxpc3QubWVzc2FnZSB9fTwvc21hbGw+XG4gICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJsaXN0LnN0YXRlID09PSAnbG9hZGluZydcIj5cbiAgICAgICAgPGkgY2xhc3M9XCJwaSBwaS1zcGluIHBpLXNwaW5uZXJcIj48L2k+IExpc3Rpbmcgb2JzZXJ2YXRpb25z4oCmXG4gICAgICA8L3NtYWxsPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImxpc3QudG90YWwgIT09IHVuZGVmaW5lZCAmJiBsaXN0LnN0YXRlICE9PSAnZW1wdHknICYmIGxpc3Quc3RhdGUgIT09ICdlcnJvcidcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNjLXNlbHR4LXN1bW1hcnlcIj5cbiAgICAgICAgICA8c3Bhbj5cbiAgICAgICAgICAgIDxiPnt7IGxpc3QudG90YWwgfCBudW1iZXIgfX08L2I+IHt7IGxpc3QudG90YWwgPT09IDEgPyAnb2JzZXJ2YXRpb24nIDogJ29ic2VydmF0aW9ucycgfX1cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaXN0Lmdyb3VwQ29sdW1uICYmIGxpc3QuZ3JvdXBzPy5sZW5ndGhcIlxuICAgICAgICAgICAgICA+wrcge3sgbGlzdC5ncm91cHMhLmxlbmd0aCB8IG51bWJlciB9fSB7eyBsaXN0Lmdyb3VwcyEubGVuZ3RoID09PSAxID8gJ2dyb3VwJyA6ICdncm91cHMnIH19IG9mXG4gICAgICAgICAgICAgIHt7IGxpc3QuZ3JvdXBDb2x1bW4gfX08L25nLWNvbnRhaW5lclxuICAgICAgICAgICAgPlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8cC1idXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwibGlzdC5ncm91cHM/Lmxlbmd0aFwiXG4gICAgICAgICAgICBpY29uPVwicGkgcGktY29weVwiXG4gICAgICAgICAgICBzaXplPVwic21hbGxcIlxuICAgICAgICAgICAgW3RleHRdPVwidHJ1ZVwiXG4gICAgICAgICAgICBwVG9vbHRpcD1cIkNvcHkgdGhlIGdyb3VwcyAoZ3JvdXAsIG9ic2VydmF0aW9ucykgYXMgdGFiLXNlcGFyYXRlZCB0ZXh0XCJcbiAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAgICAgICAob25DbGljayk9XCJjb3B5KClcIlxuICAgICAgICAgID48L3AtYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwibGlzdC50b3RhbCA9PT0gMFwiPk5vIG9ic2VydmF0aW9ucyBpbiB0aGUgc2VsZWN0aW9uLjwvc21hbGw+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJzYy1zZWx0eC1oZWFkXCIgKm5nSWY9XCJsaXN0LmNlbGxJZFwiPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2MtaGludFwiPkNlbGwgaWQ8L3NwYW4+XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1zZWx0eC1sYWJlbFwiIFt0aXRsZV09XCJsaXN0LmNlbGxJZFwiPnt7IGxpc3QuY2VsbElkIH19PC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG9sIGNsYXNzPVwic2Mtc2VsdHgtbGlzdFwiICpuZ0lmPVwibGlzdC5ncm91cHM/Lmxlbmd0aFwiIFtjbGFzcy5zdGFsZV09XCJsaXN0LnN0YXRlID09PSAnbG9hZGluZydcIj5cbiAgICAgICAgICA8bGkgKm5nRm9yPVwibGV0IGcgb2YgbGlzdC5ncm91cHM7IHRyYWNrQnk6IHRyYWNrR3JvdXBcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2Mtc2VsdHgtZ2VuZVwiIFt0aXRsZV09XCJnLm5hbWVcIlxuICAgICAgICAgICAgICA+PHNwYW4gY2xhc3M9XCJzYy1zZWx0eC1zd2F0Y2hcIiBbc3R5bGUuYmFja2dyb3VuZF09XCJnLmNvbG9yXCI+PC9zcGFuPnt7IGcubmFtZSB9fTwvc3BhblxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1zZWx0eC1iYXJcIlxuICAgICAgICAgICAgICA+PHNwYW4gW3N0eWxlLndpZHRoLiVdPVwiKDEwMCAqIGcuY291bnQpIC8gKG1heCB8fCAxKVwiIFtzdHlsZS5iYWNrZ3JvdW5kXT1cImcuY29sb3JcIj48L3NwYW5cbiAgICAgICAgICAgID48L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLXNlbHR4LWNvdW50XCI+e3sgZy5jb3VudCB8IG51bWJlciB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2xpPlxuICAgICAgICA8L29sPlxuICAgICAgICA8ZGwgY2xhc3M9XCJzYy1zZWx0eC1tZWFzdXJlc1wiICpuZ0lmPVwibGlzdC5tZWFzdXJlcz8ubGVuZ3RoXCIgW2NsYXNzLnN0YWxlXT1cImxpc3Quc3RhdGUgPT09ICdsb2FkaW5nJ1wiPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nRm9yPVwibGV0IG0gb2YgbGlzdC5tZWFzdXJlc1wiPlxuICAgICAgICAgICAgPGR0IFt0aXRsZV09XCJtLm5hbWVcIj57eyBtLm1lYW4gPyAnTWVhbiAnICsgbS5uYW1lIDogbS5uYW1lIH19PC9kdD5cbiAgICAgICAgICAgIDxkZD57eyBmb3JtYXQobSkgfX08L2RkPlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8L2RsPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG4gICAgPG5nLXRlbXBsYXRlICN3YWl0aW5nPlxuICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiPjxpIGNsYXNzPVwicGkgcGktc3BpbiBwaS1zcGlubmVyXCI+PC9pPiBMaXN0aW5nIG9ic2VydmF0aW9uc+KApjwvc21hbGw+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9kaXY+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==
@@ -0,0 +1,94 @@
1
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, NgZone, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ButtonModule } from 'primeng/button';
4
+ import { TooltipModule } from 'primeng/tooltip';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@angular/common";
7
+ import * as i2 from "primeng/button";
8
+ import * as i3 from "primeng/tooltip";
9
+ /**
10
+ * "Transcripts in selection", in the Transcripts section: the transcripts of what is selected, by
11
+ * gene, most frequent first — through the volume in spatial 3D (a cell, or a cell type picked on the
12
+ * canvas), on the plane shown in 2D (the selected cells or regions). See
13
+ * `ISpatialControls.getTranscriptsInSelection$`.
14
+ *
15
+ * Collapsible; counted only while expanded (and while the Transcripts section, which holds it, is
16
+ * open): the counts read the finest transcript tiles of the selection.
17
+ */
18
+ export class SpatialSelectionTranscriptsComponent {
19
+ constructor(zone, cdr) {
20
+ this.zone = zone;
21
+ this.cdr = cdr;
22
+ /** The spatial controls the list is read through; null without a `SPATIAL_DATA_PORT`. */
23
+ this.controls = null;
24
+ /** In spatial 3D: the list is of the whole volume. */
25
+ this.is3d = false;
26
+ /** Expanded: the list is counted and shown. */
27
+ this.expanded = true;
28
+ /** The selection's transcripts by gene (null until the first answer). */
29
+ this.list = null;
30
+ this.sub = null;
31
+ }
32
+ ngOnChanges(changes) {
33
+ if (changes['controls'])
34
+ this.watch();
35
+ }
36
+ ngOnDestroy() {
37
+ this.sub?.unsubscribe();
38
+ this.sub = null;
39
+ }
40
+ /** Whether there is a list to offer: the controls count transcripts. */
41
+ get available() {
42
+ return !!this.controls?.getTranscriptsInSelection$;
43
+ }
44
+ /** The largest gene count, for the bars. */
45
+ get max() {
46
+ return this.list?.genes?.[0]?.count ?? 0;
47
+ }
48
+ toggle() {
49
+ this.expanded = !this.expanded;
50
+ this.watch();
51
+ }
52
+ /** Subscribe while expanded, else not (a collapsed list reads nothing). */
53
+ watch() {
54
+ this.sub?.unsubscribe();
55
+ this.sub = null;
56
+ if (!this.expanded)
57
+ return;
58
+ const list$ = this.controls?.getTranscriptsInSelection$?.();
59
+ if (!list$)
60
+ return;
61
+ this.sub = list$.subscribe((state) =>
62
+ // The controls' streams may emit outside the zone.
63
+ this.zone.run(() => {
64
+ // Keep the last list on screen while the next one loads, so it does not flicker.
65
+ this.list =
66
+ state.state === 'loading' && this.list?.state === 'ready'
67
+ ? { ...this.list, state: 'loading', label: state.label ?? this.list.label }
68
+ : state;
69
+ this.cdr.markForCheck();
70
+ }));
71
+ }
72
+ /** The list as tab-separated text (gene, count), for a spreadsheet. */
73
+ copy() {
74
+ const genes = this.list?.genes;
75
+ if (!genes?.length)
76
+ return;
77
+ const text = ['gene\ttranscripts', ...genes.map((g) => `${g.name}\t${g.count}`)].join('\n');
78
+ void navigator.clipboard?.writeText(text).catch(() => undefined);
79
+ }
80
+ trackGene(_i, g) {
81
+ return g.name;
82
+ }
83
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialSelectionTranscriptsComponent, deps: [{ token: i0.NgZone }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
84
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: SpatialSelectionTranscriptsComponent, isStandalone: true, selector: "spatial-selection-transcripts", inputs: { controls: "controls", is3d: "is3d" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"available\">\n <button type=\"button\" class=\"sc-seltx-toggle sc-subhead\" [attr.aria-expanded]=\"expanded\" (click)=\"toggle()\">\n <i class=\"pi\" [class.pi-chevron-down]=\"expanded\" [class.pi-chevron-right]=\"!expanded\"></i>\n Transcripts in selection\n </button>\n <div class=\"sc-seltx\" *ngIf=\"expanded\">\n <ng-container *ngIf=\"list; else waiting\">\n <div class=\"sc-seltx-head\" *ngIf=\"list.label\">\n <span class=\"sc-seltx-label\" [title]=\"list.label\">{{ list.label }}</span>\n <small class=\"sc-hint\" *ngIf=\"list.plane\">\n plane {{ list.plane.index + 1 }} of {{ list.plane.count }}\n </small>\n <small class=\"sc-hint\" *ngIf=\"!list.plane && is3d\">whole volume</small>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'empty'\">{{ list.message }}</small>\n <small class=\"sc-hint sc-error\" *ngIf=\"list.state === 'error'\">{{ list.message }}</small>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'loading'\">\n <i class=\"pi pi-spin pi-spinner\"></i> Counting transcripts\u2026\n </small>\n <ng-container *ngIf=\"list.genes && list.state !== 'empty' && list.state !== 'error'\">\n <div class=\"sc-seltx-summary\">\n <span>\n <b>{{ list.total | number }}</b> transcripts \u00B7 {{ list.genes.length | number }} genes\n <ng-container *ngIf=\"list.cells\"\n >\u00B7 {{ list.cells | number }} {{ list.cells === 1 ? 'cell' : 'cells' }}</ng-container\n >\n </span>\n <p-button\n icon=\"pi pi-copy\"\n size=\"small\"\n [text]=\"true\"\n [disabled]=\"!list.genes.length\"\n pTooltip=\"Copy the list (gene, transcripts) as tab-separated text\"\n tooltipPosition=\"top\"\n (onClick)=\"copy()\"\n ></p-button>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.partial\">\n The selection spans more of the section than is read at once: the counts are a lower bound.\n </small>\n <small class=\"sc-hint\" *ngIf=\"!list.genes.length\">No transcripts in the selection.</small>\n <ol class=\"sc-seltx-list\" *ngIf=\"list.genes.length\" [class.stale]=\"list.state === 'loading'\">\n <li *ngFor=\"let g of list.genes; trackBy: trackGene\">\n <span class=\"sc-seltx-gene\" [title]=\"g.name\">{{ g.name }}</span>\n <span class=\"sc-seltx-bar\"><span [style.width.%]=\"(100 * g.count) / (max || 1)\"></span></span>\n <span class=\"sc-seltx-count\">{{ g.count | number }}</span>\n </li>\n </ol>\n </ng-container>\n </ng-container>\n <ng-template #waiting>\n <small class=\"sc-hint\"><i class=\"pi pi-spin pi-spinner\"></i> Counting transcripts\u2026</small>\n </ng-template>\n </div>\n</ng-container>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}.sc-subsection{display:flex;flex-direction:column;gap:.45rem}.sc-subsection-head{cursor:pointer;-webkit-user-select:none;user-select:none}.sc-subsection-head i{font-size:.65rem}.sc-subsection-head:hover .sc-subsection-title{color:var(--primary-color, #3b82f6)}.sc-subsection-body{display:flex;flex-direction:column;gap:.45rem;padding-left:.6rem;border-left:2px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}.sc-seltx-toggle{width:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;text-align:left}.sc-seltx-toggle i{font-size:.65rem}.sc-seltx-toggle:hover{color:var(--primary-color, #3b82f6)}.sc-seltx{display:flex;flex-direction:column;gap:.35rem}.sc-seltx-head{display:flex;align-items:baseline;gap:.5rem;min-width:0}.sc-seltx-label{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-summary{display:flex;align-items:center;justify-content:space-between;font-size:.78rem}.sc-seltx-list{list-style:none;margin:0;padding:0;max-height:16rem;overflow-y:auto;font-size:.78rem}.sc-seltx-list.stale{opacity:.55}.sc-seltx-list li{display:grid;grid-template-columns:minmax(4rem,7rem) 1fr auto;align-items:center;gap:.5rem;padding:.1rem 0}.sc-seltx-gene{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-bar{height:.45rem;border-radius:2px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-seltx-bar span{display:block;height:100%;background:var(--primary-color, #3b82f6)}.sc-seltx-count{font-variant-numeric:tabular-nums;text-align:right;min-width:3rem}.sc-seltx-swatch{display:inline-block;width:.6rem;height:.6rem;margin-right:.35rem;border-radius:2px;vertical-align:baseline}.sc-seltx-measures{display:grid;grid-template-columns:minmax(4rem,1fr) auto;gap:.1rem .75rem;margin:0;font-size:.78rem}.sc-seltx-measures dt{color:var(--text-color-secondary, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-measures dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}:host{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
85
+ }
86
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: SpatialSelectionTranscriptsComponent, decorators: [{
87
+ type: Component,
88
+ args: [{ selector: 'spatial-selection-transcripts', standalone: true, imports: [CommonModule, ButtonModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"available\">\n <button type=\"button\" class=\"sc-seltx-toggle sc-subhead\" [attr.aria-expanded]=\"expanded\" (click)=\"toggle()\">\n <i class=\"pi\" [class.pi-chevron-down]=\"expanded\" [class.pi-chevron-right]=\"!expanded\"></i>\n Transcripts in selection\n </button>\n <div class=\"sc-seltx\" *ngIf=\"expanded\">\n <ng-container *ngIf=\"list; else waiting\">\n <div class=\"sc-seltx-head\" *ngIf=\"list.label\">\n <span class=\"sc-seltx-label\" [title]=\"list.label\">{{ list.label }}</span>\n <small class=\"sc-hint\" *ngIf=\"list.plane\">\n plane {{ list.plane.index + 1 }} of {{ list.plane.count }}\n </small>\n <small class=\"sc-hint\" *ngIf=\"!list.plane && is3d\">whole volume</small>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'empty'\">{{ list.message }}</small>\n <small class=\"sc-hint sc-error\" *ngIf=\"list.state === 'error'\">{{ list.message }}</small>\n <small class=\"sc-hint\" *ngIf=\"list.state === 'loading'\">\n <i class=\"pi pi-spin pi-spinner\"></i> Counting transcripts\u2026\n </small>\n <ng-container *ngIf=\"list.genes && list.state !== 'empty' && list.state !== 'error'\">\n <div class=\"sc-seltx-summary\">\n <span>\n <b>{{ list.total | number }}</b> transcripts \u00B7 {{ list.genes.length | number }} genes\n <ng-container *ngIf=\"list.cells\"\n >\u00B7 {{ list.cells | number }} {{ list.cells === 1 ? 'cell' : 'cells' }}</ng-container\n >\n </span>\n <p-button\n icon=\"pi pi-copy\"\n size=\"small\"\n [text]=\"true\"\n [disabled]=\"!list.genes.length\"\n pTooltip=\"Copy the list (gene, transcripts) as tab-separated text\"\n tooltipPosition=\"top\"\n (onClick)=\"copy()\"\n ></p-button>\n </div>\n <small class=\"sc-hint\" *ngIf=\"list.partial\">\n The selection spans more of the section than is read at once: the counts are a lower bound.\n </small>\n <small class=\"sc-hint\" *ngIf=\"!list.genes.length\">No transcripts in the selection.</small>\n <ol class=\"sc-seltx-list\" *ngIf=\"list.genes.length\" [class.stale]=\"list.state === 'loading'\">\n <li *ngFor=\"let g of list.genes; trackBy: trackGene\">\n <span class=\"sc-seltx-gene\" [title]=\"g.name\">{{ g.name }}</span>\n <span class=\"sc-seltx-bar\"><span [style.width.%]=\"(100 * g.count) / (max || 1)\"></span></span>\n <span class=\"sc-seltx-count\">{{ g.count | number }}</span>\n </li>\n </ol>\n </ng-container>\n </ng-container>\n <ng-template #waiting>\n <small class=\"sc-hint\"><i class=\"pi pi-spin pi-spinner\"></i> Counting transcripts\u2026</small>\n </ng-template>\n </div>\n</ng-container>\n", styles: [".sc-hint{font-size:.75rem;color:var(--text-color-secondary, #6c757d)}.sc-error{color:var(--red-600, #c62828)}.sc-section{display:flex;flex-direction:column;gap:.35rem}.sc-lbl{font-size:.78rem;color:var(--text-color-secondary, #6c757d);white-space:nowrap}.sc-row{display:flex;align-items:center;gap:.6rem}.sc-row p-slider,.sc-row p-dropdown,.sc-row p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row p-slider .p-slider{width:100%}:host ::ng-deep .sc-row p-dropdown .p-dropdown,:host ::ng-deep .sc-row p-treeSelect .p-treeselect{width:100%}.sc-row .sc-lbl{flex:0 0 calc(50% - .6rem);min-width:0;overflow:hidden;text-overflow:ellipsis}.sc-cmap-option{display:inline-flex;align-items:center;gap:.4rem}.sc-cmap-swatch{width:3.5rem;height:.7rem;border-radius:2px;display:block}.sc-val{flex:0 0 4rem;text-align:right;font-size:.78rem;font-variant-numeric:tabular-nums;white-space:nowrap}:host ::ng-deep .sc-full,:host ::ng-deep .sc-full .p-dropdown,:host ::ng-deep .sc-full .p-autocomplete,:host ::ng-deep .sc-full input{width:100%}.sc-colorbar{height:.75rem;border-radius:2px;border:1px solid rgba(0,0,0,.2)}.sc-colorbar-ends{display:flex;justify-content:space-between;font-size:.7rem;color:var(--text-color-secondary, #6c757d);margin-top:.2rem}.sc-panel{border:1px solid var(--surface-border, #dee2e6);border-radius:6px;margin-bottom:.5rem;overflow:hidden}.sc-panel-head{display:flex;align-items:center;gap:.6rem;padding:.5rem .7rem;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--surface-100, #f5f6f7)}.sc-panel-head .sc-panel-title{flex:1;font-weight:600}.sc-panel.open>.sc-panel-head{background:var(--primary-color, #2196f3);color:var(--primary-color-text, #fff)}.sc-panel-body{display:flex;flex-direction:column;gap:.45rem;padding:.6rem .75rem .75rem}.sc-subhead{display:flex;align-items:center;gap:.5rem;margin-top:.4rem;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-color-secondary, #6c757d)}.sc-subhead:after{content:\"\";flex:1;border-top:1px solid var(--surface-border, #dee2e6)}.sc-subsection{display:flex;flex-direction:column;gap:.45rem}.sc-subsection-head{cursor:pointer;-webkit-user-select:none;user-select:none}.sc-subsection-head i{font-size:.65rem}.sc-subsection-head:hover .sc-subsection-title{color:var(--primary-color, #3b82f6)}.sc-subsection-body{display:flex;flex-direction:column;gap:.45rem;padding-left:.6rem;border-left:2px solid var(--surface-border, #dee2e6)}:host ::ng-deep .sc-buttons .p-button{padding:.35rem .75rem;font-size:.85rem}.sc-row-picker p-dropdown,.sc-row-picker p-multiSelect,.sc-row-picker p-treeSelect{flex:1 1 0;min-width:0}:host ::ng-deep .sc-row-picker .sc-variant{width:6.5rem}:host ::ng-deep .sc-row-picker p-multiselect .p-multiselect{width:100%}:host ::ng-deep .sc-row-picker p-dropdown:has(.sc-variant){flex:0 0 6.5rem}:host ::ng-deep .sc-row-picker p-treeselect:has(.sc-palette){flex:0 0 3rem}:host ::ng-deep .sc-palette .p-treeselect-label{width:0;padding:0}.sc-icon-btn{flex:0 0 auto;border:0;background:transparent;cursor:pointer;padding:.25rem .35rem;font:inherit;font-size:1.05rem;color:var(--text-color, #333);border-radius:4px}.sc-icon-btn:hover{background:var(--surface-200, #e9ecef)}.sc-icon-btn.active{color:var(--primary-color, #2196f3);font-weight:700}.sc-icon-btn:disabled{opacity:.5;cursor:default}.sc-small-btn{margin-left:auto;border:1px solid var(--surface-border, #ced4da);background:var(--surface-0, #fff);border-radius:4px;padding:.2rem .6rem;font:inherit;font-size:.8rem;cursor:pointer}:host ::ng-deep .sc-group-heading{font-size:.7rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.7}.sc-group-list,.sc-gene-tree{max-height:16rem;overflow-y:auto;border:1px solid var(--surface-border, #dee2e6);border-radius:4px;padding:.25rem .4rem}.sc-group-row,.sc-gene-row{display:flex;align-items:center;gap:.45rem;padding:.15rem 0;font-size:.88rem}.sc-group-row .sc-group-label,.sc-gene-row .sc-group-label{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-group-all,.sc-gene-root,.sc-gene-group{font-weight:600}.sc-group-all .sc-icon-btn,.sc-gene-root .sc-icon-btn,.sc-gene-group .sc-icon-btn{margin-left:auto;font-size:.85rem}.sc-count{flex:0 0 auto;font-size:.78rem;color:var(--text-color-secondary, #6c757d)}.sc-glyph-option{display:inline-flex;align-items:center;gap:.4rem}.sc-glyph-svg{width:1rem;height:1rem;fill:currentColor}:host ::ng-deep .sc-glyph-pick .p-dropdown-label{padding:.2rem .4rem}.sc-color-input{width:2.5rem;height:1.8rem;border:1px solid var(--surface-border, #ced4da);border-radius:4px;padding:0;background:none}.sc-row-number p-slider,.sc-row-range p-slider{flex:1 1 0;min-width:0}:host ::ng-deep .sc-num{width:4.5rem;padding:.3rem .4rem;text-align:center}:host ::ng-deep .sc-row-number p-inputnumber,:host ::ng-deep .sc-row-range p-inputnumber{flex:0 0 auto}.sc-gene-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:0;border:1px solid transparent;border-radius:4px;background:transparent;cursor:pointer}.sc-gene-icon:hover,.sc-gene-icon:focus-visible{border-color:var(--surface-border, rgba(0, 0, 0, .2))}.sc-seltx-toggle{width:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;text-align:left}.sc-seltx-toggle i{font-size:.65rem}.sc-seltx-toggle:hover{color:var(--primary-color, #3b82f6)}.sc-seltx{display:flex;flex-direction:column;gap:.35rem}.sc-seltx-head{display:flex;align-items:baseline;gap:.5rem;min-width:0}.sc-seltx-label{font-size:.82rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-summary{display:flex;align-items:center;justify-content:space-between;font-size:.78rem}.sc-seltx-list{list-style:none;margin:0;padding:0;max-height:16rem;overflow-y:auto;font-size:.78rem}.sc-seltx-list.stale{opacity:.55}.sc-seltx-list li{display:grid;grid-template-columns:minmax(4rem,7rem) 1fr auto;align-items:center;gap:.5rem;padding:.1rem 0}.sc-seltx-gene{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-bar{height:.45rem;border-radius:2px;background:var(--surface-200, #e9ecef);overflow:hidden}.sc-seltx-bar span{display:block;height:100%;background:var(--primary-color, #3b82f6)}.sc-seltx-count{font-variant-numeric:tabular-nums;text-align:right;min-width:3rem}.sc-seltx-swatch{display:inline-block;width:.6rem;height:.6rem;margin-right:.35rem;border-radius:2px;vertical-align:baseline}.sc-seltx-measures{display:grid;grid-template-columns:minmax(4rem,1fr) auto;gap:.1rem .75rem;margin:0;font-size:.78rem}.sc-seltx-measures dt{color:var(--text-color-secondary, #6c757d);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sc-seltx-measures dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}:host{display:contents}\n"] }]
89
+ }], ctorParameters: () => [{ type: i0.NgZone }, { type: i0.ChangeDetectorRef }], propDecorators: { controls: [{
90
+ type: Input
91
+ }], is3d: [{
92
+ type: Input
93
+ }] } });
94
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BhdGlhbC1zZWxlY3Rpb24tdHJhbnNjcmlwdHMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zcGF0aWFsLWNvbnRyb2xzL3NwYXRpYWwtc2VsZWN0aW9uLXRyYW5zY3JpcHRzL3NwYXRpYWwtc2VsZWN0aW9uLXRyYW5zY3JpcHRzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc3BhdGlhbC1jb250cm9scy9zcGF0aWFsLXNlbGVjdGlvbi10cmFuc2NyaXB0cy9zcGF0aWFsLXNlbGVjdGlvbi10cmFuc2NyaXB0cy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sR0FJUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7QUFNaEQ7Ozs7Ozs7O0dBUUc7QUFTSCxNQUFNLE9BQU8sb0NBQW9DO0lBWS9DLFlBQ21CLElBQVksRUFDWixHQUFzQjtRQUR0QixTQUFJLEdBQUosSUFBSSxDQUFRO1FBQ1osUUFBRyxHQUFILEdBQUcsQ0FBbUI7UUFiekMseUZBQXlGO1FBQ2hGLGFBQVEsR0FBNEIsSUFBSSxDQUFDO1FBQ2xELHNEQUFzRDtRQUM3QyxTQUFJLEdBQUcsS0FBSyxDQUFDO1FBRXRCLCtDQUErQztRQUNyQyxhQUFRLEdBQUcsSUFBSSxDQUFDO1FBQzFCLHlFQUF5RTtRQUMvRCxTQUFJLEdBQWtDLElBQUksQ0FBQztRQUM3QyxRQUFHLEdBQXdCLElBQUksQ0FBQztJQUtyQyxDQUFDO0lBRUosV0FBVyxDQUFDLE9B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LEVBQUUsYUFBYSxDQUFDLG1CQUduQyx1QkFBdUIsQ0FBQyxNQUFNOzJHQUl0QyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLElBQUk7c0JBQVosS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBJbnB1dCxcbiAgTmdab25lLFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9idXR0b24nO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHR5cGUgeyBJU3BhdGlhbENvbnRyb2xzIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL3Zpc3VhbGl6ZXIuY29udHJhY3QnO1xuaW1wb3J0IHR5cGUgeyBUcmFuc2NyaXB0c0luU2VsZWN0aW9uIH0gZnJvbSAnLi4vLi4vY29udHJhY3RzL2Rpc3BsYXktdHlwZXMnO1xuXG4vKipcbiAqIFwiVHJhbnNjcmlwdHMgaW4gc2VsZWN0aW9uXCIsIGluIHRoZSBUcmFuc2NyaXB0cyBzZWN0aW9uOiB0aGUgdHJhbnNjcmlwdHMgb2Ygd2hhdCBpcyBzZWxlY3RlZCwgYnlcbiAqIGdlbmUsIG1vc3QgZnJlcXVlbnQgZmlyc3Qg4oCUIHRocm91Z2ggdGhlIHZvbHVtZSBpbiBzcGF0aWFsIDNEIChhIGNlbGwsIG9yIGEgY2VsbCB0eXBlIHBpY2tlZCBvbiB0aGVcbiAqIGNhbnZhcyksIG9uIHRoZSBwbGFuZSBzaG93biBpbiAyRCAodGhlIHNlbGVjdGVkIGNlbGxzIG9yIHJlZ2lvbnMpLiBTZWVcbiAqIGBJU3BhdGlhbENvbnRyb2xzLmdldFRyYW5zY3JpcHRzSW5TZWxlY3Rpb24kYC5cbiAqXG4gKiBDb2xsYXBzaWJsZTsgY291bnRlZCBvbmx5IHdoaWxlIGV4cGFuZGVkIChhbmQgd2hpbGUgdGhlIFRyYW5zY3JpcHRzIHNlY3Rpb24sIHdoaWNoIGhvbGRzIGl0LCBpc1xuICogb3Blbik6IHRoZSBjb3VudHMgcmVhZCB0aGUgZmluZXN0IHRyYW5zY3JpcHQgdGlsZXMgb2YgdGhlIHNlbGVjdGlvbi5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnc3BhdGlhbC1zZWxlY3Rpb24tdHJhbnNjcmlwdHMnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBCdXR0b25Nb2R1bGUsIFRvb2x0aXBNb2R1bGVdLFxuICB0ZW1wbGF0ZVVybDogJy4vc3BhdGlhbC1zZWxlY3Rpb24tdHJhbnNjcmlwdHMuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9zcGF0aWFsLXNlbGVjdGlvbi10cmFuc2NyaXB0cy5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU3BhdGlhbFNlbGVjdGlvblRyYW5zY3JpcHRzQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuICAvKiogVGhlIHNwYXRpYWwgY29udHJvbHMgdGhlIGxpc3QgaXMgcmVhZCB0aHJvdWdoOyBudWxsIHdpdGhvdXQgYSBgU1BBVElBTF9EQVRBX1BPUlRgLiAqL1xuICBASW5wdXQoKSBjb250cm9sczogSVNwYXRpYWxDb250cm9scyB8IG51bGwgPSBudWxsO1xuICAvKiogSW4gc3BhdGlhbCAzRDogdGhlIGxpc3QgaXMgb2YgdGhlIHdob2xlIHZvbHVtZS4gKi9cbiAgQElucHV0KCkgaXMzZCA9IGZhbHNlO1xuXG4gIC8qKiBFeHBhbmRlZDogdGhlIGxpc3QgaXMgY291bnRlZCBhbmQgc2hvd24uICovXG4gIHByb3RlY3RlZCBleHBhbmRlZCA9IHRydWU7XG4gIC8qKiBUaGUgc2VsZWN0aW9uJ3MgdHJhbnNjcmlwdHMgYnkgZ2VuZSAobnVsbCB1bnRpbCB0aGUgZmlyc3QgYW5zd2VyKS4gKi9cbiAgcHJvdGVjdGVkIGxpc3Q6IFRyYW5zY3JpcHRzSW5TZWxlY3Rpb24gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzdWI6IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgem9uZTogTmdab25lLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY2RyOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgKSB7fVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICBpZiAoY2hhbmdlc1snY29udHJvbHMnXSkgdGhpcy53YXRjaCgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5zdWI/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5zdWIgPSBudWxsO1xuICB9XG5cbiAgLyoqIFdoZXRoZXIgdGhlcmUgaXMgYSBsaXN0IHRvIG9mZmVyOiB0aGUgY29udHJvbHMgY291bnQgdHJhbnNjcmlwdHMuICovXG4gIHByb3RlY3RlZCBnZXQgYXZhaWxhYmxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMuY29udHJvbHM/LmdldFRyYW5zY3JpcHRzSW5TZWxlY3Rpb24kO1xuICB9XG5cbiAgLyoqIFRoZSBsYXJnZXN0IGdlbmUgY291bnQsIGZvciB0aGUgYmFycy4gKi9cbiAgcHJvdGVjdGVkIGdldCBtYXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5saXN0Py5nZW5lcz8uWzBdPy5jb3VudCA/PyAwO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRvZ2dsZSgpOiB2b2lkIHtcbiAgICB0aGlzLmV4cGFuZGVkID0gIXRoaXMuZXhwYW5kZWQ7XG4gICAgdGhpcy53YXRjaCgpO1xuICB9XG5cbiAgLyoqIFN1YnNjcmliZSB3aGlsZSBleHBhbmRlZCwgZWxzZSBub3QgKGEgY29sbGFwc2VkIGxpc3QgcmVhZHMgbm90aGluZykuICovXG4gIHByaXZhdGUgd2F0Y2goKTogdm9pZCB7XG4gICAgdGhpcy5zdWI/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5zdWIgPSBudWxsO1xuICAgIGlmICghdGhpcy5leHBhbmRlZCkgcmV0dXJuO1xuICAgIGNvbnN0IGxpc3QkID0gdGhpcy5jb250cm9scz8uZ2V0VHJhbnNjcmlwdHNJblNlbGVjdGlvbiQ/LigpO1xuICAgIGlmICghbGlzdCQpIHJldHVybjtcbiAgICB0aGlzLnN1YiA9IGxpc3QkLnN1YnNjcmliZSgoc3RhdGUpID0+XG4gICAgICAvLyBUaGUgY29udHJvbHMnIHN0cmVhbXMgbWF5IGVtaXQgb3V0c2lkZSB0aGUgem9uZS5cbiAgICAgIHRoaXMuem9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAvLyBLZWVwIHRoZSBsYXN0IGxpc3Qgb24gc2NyZWVuIHdoaWxlIHRoZSBuZXh0IG9uZSBsb2Fkcywgc28gaXQgZG9lcyBub3QgZmxpY2tlci5cbiAgICAgICAgdGhpcy5saXN0ID1cbiAgICAgICAgICBzdGF0ZS5zdGF0ZSA9PT0gJ2xvYWRpbmcnICYmIHRoaXMubGlzdD8uc3RhdGUgPT09ICdyZWFkeSdcbiAgICAgICAgICAgID8geyAuLi50aGlzLmxpc3QsIHN0YXRlOiAnbG9hZGluZycsIGxhYmVsOiBzdGF0ZS5sYWJlbCA/PyB0aGlzLmxpc3QubGFiZWwgfVxuICAgICAgICAgICAgOiBzdGF0ZTtcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICB9KSxcbiAgICApO1xuICB9XG5cbiAgLyoqIFRoZSBsaXN0IGFzIHRhYi1zZXBhcmF0ZWQgdGV4dCAoZ2VuZSwgY291bnQpLCBmb3IgYSBzcHJlYWRzaGVldC4gKi9cbiAgcHJvdGVjdGVkIGNvcHkoKTogdm9pZCB7XG4gICAgY29uc3QgZ2VuZXMgPSB0aGlzLmxpc3Q/LmdlbmVzO1xuICAgIGlmICghZ2VuZXM/Lmxlbmd0aCkgcmV0dXJuO1xuICAgIGNvbnN0IHRleHQgPSBbJ2dlbmVcXHR0cmFuc2NyaXB0cycsIC4uLmdlbmVzLm1hcCgoZykgPT4gYCR7Zy5uYW1lfVxcdCR7Zy5jb3VudH1gKV0uam9pbignXFxuJyk7XG4gICAgdm9pZCBuYXZpZ2F0b3IuY2xpcGJvYXJkPy53cml0ZVRleHQodGV4dCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgfVxuXG4gIHByb3RlY3RlZCB0cmFja0dlbmUoX2k6IG51bWJlciwgZzogeyBuYW1lOiBzdHJpbmcgfSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGcubmFtZTtcbiAgfVxufVxuIiwiPG5nLWNvbnRhaW5lciAqbmdJZj1cImF2YWlsYWJsZVwiPlxuICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cInNjLXNlbHR4LXRvZ2dsZSBzYy1zdWJoZWFkXCIgW2F0dHIuYXJpYS1leHBhbmRlZF09XCJleHBhbmRlZFwiIChjbGljayk9XCJ0b2dnbGUoKVwiPlxuICAgIDxpIGNsYXNzPVwicGlcIiBbY2xhc3MucGktY2hldnJvbi1kb3duXT1cImV4cGFuZGVkXCIgW2NsYXNzLnBpLWNoZXZyb24tcmlnaHRdPVwiIWV4cGFuZGVkXCI+PC9pPlxuICAgIFRyYW5zY3JpcHRzIGluIHNlbGVjdGlvblxuICA8L2J1dHRvbj5cbiAgPGRpdiBjbGFzcz1cInNjLXNlbHR4XCIgKm5nSWY9XCJleHBhbmRlZFwiPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaXN0OyBlbHNlIHdhaXRpbmdcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJzYy1zZWx0eC1oZWFkXCIgKm5nSWY9XCJsaXN0LmxhYmVsXCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwic2Mtc2VsdHgtbGFiZWxcIiBbdGl0bGVdPVwibGlzdC5sYWJlbFwiPnt7IGxpc3QubGFiZWwgfX08L3NwYW4+XG4gICAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cImxpc3QucGxhbmVcIj5cbiAgICAgICAgICBwbGFuZSB7eyBsaXN0LnBsYW5lLmluZGV4ICsgMSB9fSBvZiB7eyBsaXN0LnBsYW5lLmNvdW50IH19XG4gICAgICAgIDwvc21hbGw+XG4gICAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIiAqbmdJZj1cIiFsaXN0LnBsYW5lICYmIGlzM2RcIj53aG9sZSB2b2x1bWU8L3NtYWxsPlxuICAgICAgPC9kaXY+XG4gICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCJsaXN0LnN0YXRlID09PSAnZW1wdHknXCI+e3sgbGlzdC5tZXNzYWdlIH19PC9zbWFsbD5cbiAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnQgc2MtZXJyb3JcIiAqbmdJZj1cImxpc3Quc3RhdGUgPT09ICdlcnJvcidcIj57eyBsaXN0Lm1lc3NhZ2UgfX08L3NtYWxsPlxuICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwibGlzdC5zdGF0ZSA9PT0gJ2xvYWRpbmcnXCI+XG4gICAgICAgIDxpIGNsYXNzPVwicGkgcGktc3BpbiBwaS1zcGlubmVyXCI+PC9pPiBDb3VudGluZyB0cmFuc2NyaXB0c+KAplxuICAgICAgPC9zbWFsbD5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaXN0LmdlbmVzICYmIGxpc3Quc3RhdGUgIT09ICdlbXB0eScgJiYgbGlzdC5zdGF0ZSAhPT0gJ2Vycm9yJ1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2Mtc2VsdHgtc3VtbWFyeVwiPlxuICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgPGI+e3sgbGlzdC50b3RhbCB8IG51bWJlciB9fTwvYj4gdHJhbnNjcmlwdHMgwrcge3sgbGlzdC5nZW5lcy5sZW5ndGggfCBudW1iZXIgfX0gZ2VuZXNcbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsaXN0LmNlbGxzXCJcbiAgICAgICAgICAgICAgPsK3IHt7IGxpc3QuY2VsbHMgfCBudW1iZXIgfX0ge3sgbGlzdC5jZWxscyA9PT0gMSA/ICdjZWxsJyA6ICdjZWxscycgfX08L25nLWNvbnRhaW5lclxuICAgICAgICAgICAgPlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8cC1idXR0b25cbiAgICAgICAgICAgIGljb249XCJwaSBwaS1jb3B5XCJcbiAgICAgICAgICAgIHNpemU9XCJzbWFsbFwiXG4gICAgICAgICAgICBbdGV4dF09XCJ0cnVlXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhbGlzdC5nZW5lcy5sZW5ndGhcIlxuICAgICAgICAgICAgcFRvb2x0aXA9XCJDb3B5IHRoZSBsaXN0IChnZW5lLCB0cmFuc2NyaXB0cykgYXMgdGFiLXNlcGFyYXRlZCB0ZXh0XCJcbiAgICAgICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiXG4gICAgICAgICAgICAob25DbGljayk9XCJjb3B5KClcIlxuICAgICAgICAgID48L3AtYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPHNtYWxsIGNsYXNzPVwic2MtaGludFwiICpuZ0lmPVwibGlzdC5wYXJ0aWFsXCI+XG4gICAgICAgICAgVGhlIHNlbGVjdGlvbiBzcGFucyBtb3JlIG9mIHRoZSBzZWN0aW9uIHRoYW4gaXMgcmVhZCBhdCBvbmNlOiB0aGUgY291bnRzIGFyZSBhIGxvd2VyIGJvdW5kLlxuICAgICAgICA8L3NtYWxsPlxuICAgICAgICA8c21hbGwgY2xhc3M9XCJzYy1oaW50XCIgKm5nSWY9XCIhbGlzdC5nZW5lcy5sZW5ndGhcIj5ObyB0cmFuc2NyaXB0cyBpbiB0aGUgc2VsZWN0aW9uLjwvc21hbGw+XG4gICAgICAgIDxvbCBjbGFzcz1cInNjLXNlbHR4LWxpc3RcIiAqbmdJZj1cImxpc3QuZ2VuZXMubGVuZ3RoXCIgW2NsYXNzLnN0YWxlXT1cImxpc3Quc3RhdGUgPT09ICdsb2FkaW5nJ1wiPlxuICAgICAgICAgIDxsaSAqbmdGb3I9XCJsZXQgZyBvZiBsaXN0LmdlbmVzOyB0cmFja0J5OiB0cmFja0dlbmVcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwic2Mtc2VsdHgtZ2VuZVwiIFt0aXRsZV09XCJnLm5hbWVcIj57eyBnLm5hbWUgfX08L3NwYW4+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cInNjLXNlbHR4LWJhclwiPjxzcGFuIFtzdHlsZS53aWR0aC4lXT1cIigxMDAgKiBnLmNvdW50KSAvIChtYXggfHwgMSlcIj48L3NwYW4+PC9zcGFuPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJzYy1zZWx0eC1jb3VudFwiPnt7IGcuY291bnQgfCBudW1iZXIgfX08L3NwYW4+XG4gICAgICAgICAgPC9saT5cbiAgICAgICAgPC9vbD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxuZy10ZW1wbGF0ZSAjd2FpdGluZz5cbiAgICAgIDxzbWFsbCBjbGFzcz1cInNjLWhpbnRcIj48aSBjbGFzcz1cInBpIHBpLXNwaW4gcGktc3Bpbm5lclwiPjwvaT4gQ291bnRpbmcgdHJhbnNjcmlwdHPigKY8L3NtYWxsPlxuICAgIDwvbmctdGVtcGxhdGU+XG4gIDwvZGl2PlxuPC9uZy1jb250YWluZXI+XG4iXX0=