@jbrowse/plugin-variants 3.3.0 → 3.4.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/dist/LinearVariantDisplay/model.d.ts +1 -1
- package/dist/MultiLinearVariantDisplay/model.d.ts +1 -1
- package/dist/MultiLinearVariantMatrixDisplay/model.d.ts +1 -1
- package/dist/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +7 -8
- package/dist/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +3 -3
- package/dist/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -1
- package/dist/MultiLinearVariantMatrixRenderer/makeImageData.js +61 -6
- package/dist/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +4 -4
- package/dist/MultiLinearVariantRenderer/MultiVariantRenderer.js +3 -3
- package/dist/MultiLinearVariantRenderer/makeImageData.js +79 -48
- package/dist/MultiLinearVariantRenderer/types.d.ts +1 -0
- package/dist/MultiVariantBaseRenderer.d.ts +4 -4
- package/dist/SplitVcfTabixAdapter/SplitVcfTabixAdapter.d.ts +0 -1
- package/dist/SplitVcfTabixAdapter/SplitVcfTabixAdapter.js +0 -1
- package/dist/VariantFeatureWidget/VariantFeatureWidget.js +9 -4
- package/dist/VariantFeatureWidget/stateModelFactory.d.ts +9 -6
- package/dist/VariantRPC/getGenotypeMatrix.js +10 -2
- package/dist/VcfAdapter/VcfAdapter.d.ts +0 -1
- package/dist/VcfAdapter/VcfAdapter.js +0 -1
- package/dist/VcfTabixAdapter/VcfTabixAdapter.d.ts +0 -1
- package/dist/VcfTabixAdapter/VcfTabixAdapter.js +0 -1
- package/dist/shared/MultiVariantBaseModel.d.ts +1 -1
- package/dist/shared/SharedVariantMixin.d.ts +1 -1
- package/dist/shared/drawAlleleCount.d.ts +2 -1
- package/dist/shared/drawAlleleCount.js +22 -44
- package/dist/shared/minorAlleleFrequencyUtils.d.ts +3 -3
- package/dist/shared/minorAlleleFrequencyUtils.js +15 -9
- package/esm/LinearVariantDisplay/model.d.ts +1 -1
- package/esm/MultiLinearVariantDisplay/model.d.ts +1 -1
- package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +1 -1
- package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +7 -8
- package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +3 -3
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -1
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.js +62 -7
- package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +4 -4
- package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.js +3 -3
- package/esm/MultiLinearVariantRenderer/makeImageData.js +81 -50
- package/esm/MultiLinearVariantRenderer/types.d.ts +1 -0
- package/esm/MultiVariantBaseRenderer.d.ts +4 -4
- package/esm/SplitVcfTabixAdapter/SplitVcfTabixAdapter.d.ts +0 -1
- package/esm/SplitVcfTabixAdapter/SplitVcfTabixAdapter.js +0 -1
- package/esm/VariantFeatureWidget/VariantFeatureWidget.js +9 -4
- package/esm/VariantFeatureWidget/stateModelFactory.d.ts +9 -6
- package/esm/VariantRPC/getGenotypeMatrix.js +10 -2
- package/esm/VcfAdapter/VcfAdapter.d.ts +0 -1
- package/esm/VcfAdapter/VcfAdapter.js +0 -1
- package/esm/VcfTabixAdapter/VcfTabixAdapter.d.ts +0 -1
- package/esm/VcfTabixAdapter/VcfTabixAdapter.js +0 -1
- package/esm/shared/MultiVariantBaseModel.d.ts +1 -1
- package/esm/shared/SharedVariantMixin.d.ts +1 -1
- package/esm/shared/drawAlleleCount.d.ts +2 -1
- package/esm/shared/drawAlleleCount.js +21 -44
- package/esm/shared/minorAlleleFrequencyUtils.d.ts +3 -3
- package/esm/shared/minorAlleleFrequencyUtils.js +15 -9
- package/package.json +8 -8
|
@@ -3,9 +3,9 @@ import type { Instance } from 'mobx-state-tree';
|
|
|
3
3
|
export declare function stateModelFactory(pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
|
|
4
4
|
id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
5
5
|
type: import("mobx-state-tree").ISimpleType<"BaseFeatureWidget">;
|
|
6
|
-
featureData: import("mobx-state-tree").IType<
|
|
6
|
+
featureData: import("mobx-state-tree").IType<import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat>;
|
|
7
7
|
formattedFields: import("mobx-state-tree").IType<any, any, any>;
|
|
8
|
-
unformattedFeatureData: import("mobx-state-tree").IType<
|
|
8
|
+
unformattedFeatureData: import("mobx-state-tree").IType<import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat>;
|
|
9
9
|
view: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IReferenceType<import("mobx-state-tree").IAnyType>>;
|
|
10
10
|
track: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IReferenceType<import("mobx-state-tree").IAnyType>>;
|
|
11
11
|
trackId: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
|
|
@@ -35,15 +35,16 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
35
35
|
} & {
|
|
36
36
|
afterAttach(): void;
|
|
37
37
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>, [undefined]>;
|
|
38
|
+
descriptions: import("mobx-state-tree").IType<Record<string, unknown> | undefined, Record<string, unknown> | undefined, Record<string, unknown> | undefined>;
|
|
38
39
|
} & {
|
|
39
40
|
type: import("mobx-state-tree").ISimpleType<"VariantFeatureWidget">;
|
|
40
41
|
descriptions: import("mobx-state-tree").IType<any, any, any>;
|
|
41
42
|
}, {
|
|
42
43
|
error: unknown;
|
|
43
44
|
} & {
|
|
44
|
-
setFeatureData(featureData:
|
|
45
|
+
setFeatureData(featureData: import("@jbrowse/core/util").SimpleFeatureSerialized): void;
|
|
45
46
|
clearFeatureData(): void;
|
|
46
|
-
setFormattedData(feat:
|
|
47
|
+
setFormattedData(feat: import("@jbrowse/core/util").SimpleFeatureSerialized): void;
|
|
47
48
|
setExtra(type?: string, trackId?: string, maxDepth?: number): void;
|
|
48
49
|
setError(e: unknown): void;
|
|
49
50
|
} & {
|
|
@@ -53,9 +54,9 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
53
54
|
} & Partial<import("mobx-state-tree/dist/internal").ExtractCFromProps<{
|
|
54
55
|
id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
55
56
|
type: import("mobx-state-tree").ISimpleType<"BaseFeatureWidget">;
|
|
56
|
-
featureData: import("mobx-state-tree").IType<
|
|
57
|
+
featureData: import("mobx-state-tree").IType<import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat>;
|
|
57
58
|
formattedFields: import("mobx-state-tree").IType<any, any, any>;
|
|
58
|
-
unformattedFeatureData: import("mobx-state-tree").IType<
|
|
59
|
+
unformattedFeatureData: import("mobx-state-tree").IType<import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat, import("@jbrowse/core/BaseFeatureWidget/types").MaybeSerializedFeat>;
|
|
59
60
|
view: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IReferenceType<import("mobx-state-tree").IAnyType>>;
|
|
60
61
|
track: import("mobx-state-tree").IMaybe<import("mobx-state-tree").IReferenceType<import("mobx-state-tree").IAnyType>>;
|
|
61
62
|
trackId: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
|
|
@@ -85,6 +86,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
85
86
|
} & {
|
|
86
87
|
afterAttach(): void;
|
|
87
88
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>, [undefined]>;
|
|
89
|
+
descriptions: import("mobx-state-tree").IType<Record<string, unknown> | undefined, Record<string, unknown> | undefined, Record<string, unknown> | undefined>;
|
|
88
90
|
}>> & import("mobx-state-tree/dist/internal").NonEmptyObject & import("mobx-state-tree")._NotCustomized, {
|
|
89
91
|
type: "BaseFeatureWidget";
|
|
90
92
|
id: string;
|
|
@@ -95,6 +97,7 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
95
97
|
maxDepth: number | undefined;
|
|
96
98
|
sequenceFeatureDetails: import("mobx-state-tree").ModelSnapshotType<{}>;
|
|
97
99
|
formattedFields: any;
|
|
100
|
+
descriptions: Record<string, unknown> | undefined;
|
|
98
101
|
finalizedFeatureData: any;
|
|
99
102
|
} & import("mobx-state-tree")._NotCustomized>;
|
|
100
103
|
export type VariantFeatureWidgetStateModel = ReturnType<typeof stateModelFactory>;
|
|
@@ -14,11 +14,12 @@ export async function getGenotypeMatrix({ pluginManager, args, }) {
|
|
|
14
14
|
features: await firstValueFrom(dataAdapter.getFeaturesInMultipleRegions(regions, args).pipe(toArray())),
|
|
15
15
|
});
|
|
16
16
|
for (const { alleleCounts } of mafs) {
|
|
17
|
-
for (const alt of
|
|
17
|
+
for (const alt of Object.keys(alleleCounts)) {
|
|
18
18
|
genotypeFactor.add(alt);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
const rows = {};
|
|
22
|
+
const cacheSplit = {};
|
|
22
23
|
forEachWithStopTokenCheck(mafs, stopToken, ({ feature }) => {
|
|
23
24
|
const genotypes = feature.get('genotypes');
|
|
24
25
|
for (const { name } of sources) {
|
|
@@ -26,7 +27,14 @@ export async function getGenotypeMatrix({ pluginManager, args, }) {
|
|
|
26
27
|
rows[name] = [];
|
|
27
28
|
}
|
|
28
29
|
const val = genotypes[name];
|
|
29
|
-
|
|
30
|
+
let alleles;
|
|
31
|
+
if (cacheSplit[val]) {
|
|
32
|
+
alleles = cacheSplit[val];
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
alleles = val.split(/[/|]/);
|
|
36
|
+
cacheSplit[val] = alleles;
|
|
37
|
+
}
|
|
30
38
|
let genotypeStatus = 0;
|
|
31
39
|
let nonRefCount = 0;
|
|
32
40
|
let uncalledCount = 0;
|
|
@@ -205,7 +205,7 @@ export default function MultiVariantBaseModelF(configSchema: AnyConfigurationSch
|
|
|
205
205
|
} & {
|
|
206
206
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
207
207
|
deleteBlock(key: string): void;
|
|
208
|
-
selectFeature(feature: Feature): void
|
|
208
|
+
selectFeature(feature: Feature): Promise<void>;
|
|
209
209
|
navToFeature(feature: Feature): void;
|
|
210
210
|
clearFeatureSelection(): void;
|
|
211
211
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -193,7 +193,7 @@ export default function SharedVariantMixin(configSchema: AnyConfigurationSchemaT
|
|
|
193
193
|
} & {
|
|
194
194
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
195
195
|
deleteBlock(key: string): void;
|
|
196
|
-
selectFeature(feature: Feature): void
|
|
196
|
+
selectFeature(feature: Feature): Promise<void>;
|
|
197
197
|
navToFeature(feature: Feature): void;
|
|
198
198
|
clearFeatureSelection(): void;
|
|
199
199
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function getColorAlleleCount(ref: number, alt: number, alt2: number, uncalled: number, total: number, drawReference?: boolean): any;
|
|
2
|
+
export declare function drawColorAlleleCount(c: string, ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, featureType?: string, featureStrand?: number, alpha?: number): void;
|
|
@@ -1,27 +1,8 @@
|
|
|
1
1
|
import { colord } from '@jbrowse/core/util/colord';
|
|
2
2
|
import { f2 } from './constants';
|
|
3
|
-
function getColorAlleleCount(
|
|
4
|
-
const total = alleles.length;
|
|
5
|
-
let alt = 0;
|
|
6
|
-
let uncalled = 0;
|
|
7
|
-
let alt2 = 0;
|
|
8
|
-
let ref = 0;
|
|
9
|
-
for (const allele of alleles) {
|
|
10
|
-
if (allele === mostFrequentAlt) {
|
|
11
|
-
alt++;
|
|
12
|
-
}
|
|
13
|
-
else if (allele === '0') {
|
|
14
|
-
ref++;
|
|
15
|
-
}
|
|
16
|
-
else if (allele === '.') {
|
|
17
|
-
uncalled++;
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
alt2++;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
3
|
+
export function getColorAlleleCount(ref, alt, alt2, uncalled, total, drawReference = true) {
|
|
23
4
|
if (ref === total) {
|
|
24
|
-
return drawReference ? '#ccc' :
|
|
5
|
+
return drawReference ? '#ccc' : '';
|
|
25
6
|
}
|
|
26
7
|
else {
|
|
27
8
|
let a1;
|
|
@@ -39,31 +20,27 @@ function getColorAlleleCount(alleles, mostFrequentAlt, drawReference = true) {
|
|
|
39
20
|
return (a1 === null || a1 === void 0 ? void 0 : a1.toHex()) || 'black';
|
|
40
21
|
}
|
|
41
22
|
}
|
|
42
|
-
export function drawColorAlleleCount(
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
ctx.closePath();
|
|
53
|
-
ctx.fill();
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
ctx.beginPath();
|
|
57
|
-
ctx.moveTo(x + w + f2, y - f2);
|
|
58
|
-
ctx.lineTo(x + w + f2, y + h + f2);
|
|
59
|
-
ctx.lineTo(x - f2, y + h / 2);
|
|
60
|
-
ctx.closePath();
|
|
61
|
-
ctx.fill();
|
|
62
|
-
}
|
|
23
|
+
export function drawColorAlleleCount(c, ctx, x, y, w, h, featureType = '', featureStrand, alpha = 1) {
|
|
24
|
+
ctx.fillStyle = alpha !== 1 ? colord(c).alpha(alpha).toHex() : c;
|
|
25
|
+
if (featureType === 'inversion') {
|
|
26
|
+
if (featureStrand === 1) {
|
|
27
|
+
ctx.beginPath();
|
|
28
|
+
ctx.moveTo(x - f2, y - f2);
|
|
29
|
+
ctx.lineTo(x - f2, y + h + f2);
|
|
30
|
+
ctx.lineTo(x + w + f2, y + h / 2);
|
|
31
|
+
ctx.closePath();
|
|
32
|
+
ctx.fill();
|
|
63
33
|
}
|
|
64
34
|
else {
|
|
65
|
-
ctx.
|
|
35
|
+
ctx.beginPath();
|
|
36
|
+
ctx.moveTo(x + w + f2, y - f2);
|
|
37
|
+
ctx.lineTo(x + w + f2, y + h + f2);
|
|
38
|
+
ctx.lineTo(x - f2, y + h / 2);
|
|
39
|
+
ctx.closePath();
|
|
40
|
+
ctx.fill();
|
|
66
41
|
}
|
|
67
42
|
}
|
|
68
|
-
|
|
43
|
+
else {
|
|
44
|
+
ctx.fillRect(x - f2, y - f2, w + f2, h + f2);
|
|
45
|
+
}
|
|
69
46
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Feature } from '@jbrowse/core/util';
|
|
2
2
|
export declare function findSecondLargestNumber(arr: Iterable<number>): number;
|
|
3
|
-
export declare function calculateAlleleCounts(feat: Feature):
|
|
4
|
-
export declare function calculateMinorAlleleFrequency(alleleCounts:
|
|
3
|
+
export declare function calculateAlleleCounts(feat: Feature): Record<string, number>;
|
|
4
|
+
export declare function calculateMinorAlleleFrequency(alleleCounts: Record<string, number>): number;
|
|
5
5
|
export declare function getFeaturesThatPassMinorAlleleFrequencyFilter({ features, minorAlleleFrequencyFilter, lengthCutoffFilter, stopToken, }: {
|
|
6
6
|
features: Iterable<Feature>;
|
|
7
7
|
minorAlleleFrequencyFilter: number;
|
|
@@ -10,5 +10,5 @@ export declare function getFeaturesThatPassMinorAlleleFrequencyFilter({ features
|
|
|
10
10
|
}): {
|
|
11
11
|
feature: Feature;
|
|
12
12
|
mostFrequentAlt: string;
|
|
13
|
-
alleleCounts:
|
|
13
|
+
alleleCounts: Record<string, number>;
|
|
14
14
|
}[];
|
|
@@ -14,24 +14,30 @@ export function findSecondLargestNumber(arr) {
|
|
|
14
14
|
return secondMax;
|
|
15
15
|
}
|
|
16
16
|
export function calculateAlleleCounts(feat) {
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
var _a;
|
|
18
|
+
const genotypes = feat.get('genotypes');
|
|
19
|
+
const alleleCounts = { 0: 0, 1: 0, '.': 0 };
|
|
20
|
+
const cacheSplit = {};
|
|
21
|
+
const vals = Object.values(genotypes);
|
|
22
|
+
const len = vals.length;
|
|
23
|
+
for (let i = 0; i < len; i++) {
|
|
24
|
+
const genotype = vals[i];
|
|
25
|
+
const alleles = cacheSplit[genotype] || (cacheSplit[genotype] = genotype.split(/[/|]/));
|
|
26
|
+
for (let i = 0, len = alleles.length; i < len; i++) {
|
|
27
|
+
const a = alleles[i];
|
|
28
|
+
alleleCounts[a] = ((_a = alleleCounts[a]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
return alleleCounts;
|
|
26
32
|
}
|
|
27
33
|
export function calculateMinorAlleleFrequency(alleleCounts) {
|
|
28
|
-
return (findSecondLargestNumber(
|
|
29
|
-
(sum(
|
|
34
|
+
return (findSecondLargestNumber(Object.values(alleleCounts)) /
|
|
35
|
+
(sum(Object.values(alleleCounts)) || 1));
|
|
30
36
|
}
|
|
31
37
|
function getMostFrequentAlt(alleleCounts) {
|
|
32
38
|
let mostFrequentAlt;
|
|
33
39
|
let max = 0;
|
|
34
|
-
for (const [alt, altCount] of
|
|
40
|
+
for (const [alt, altCount] of Object.entries(alleleCounts)) {
|
|
35
41
|
if (alt !== '.' && alt !== '0') {
|
|
36
42
|
if (altCount > max) {
|
|
37
43
|
mostFrequentAlt = alt;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-variants",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "JBrowse 2 variant adapters, tracks, etc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@flatten-js/interval-tree": "^1.0.15",
|
|
40
|
-
"@gmod/bgzf-filehandle": "^
|
|
41
|
-
"@gmod/tabix": "^
|
|
40
|
+
"@gmod/bgzf-filehandle": "^3.0.2",
|
|
41
|
+
"@gmod/tabix": "^3.0.1",
|
|
42
42
|
"@gmod/vcf": "^6.0.8",
|
|
43
|
-
"@jbrowse/core": "^3.
|
|
44
|
-
"@jbrowse/plugin-circular-view": "^3.
|
|
45
|
-
"@jbrowse/plugin-linear-genome-view": "^3.
|
|
46
|
-
"@jbrowse/sv-core": "^3.
|
|
43
|
+
"@jbrowse/core": "^3.4.0",
|
|
44
|
+
"@jbrowse/plugin-circular-view": "^3.4.0",
|
|
45
|
+
"@jbrowse/plugin-linear-genome-view": "^3.4.0",
|
|
46
|
+
"@jbrowse/sv-core": "^3.4.0",
|
|
47
47
|
"@mui/icons-material": "^7.0.0",
|
|
48
48
|
"@mui/material": "^7.0.0",
|
|
49
49
|
"@mui/x-data-grid": "^8.0.0",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"distModule": "esm/index.js",
|
|
64
64
|
"srcModule": "src/index.ts",
|
|
65
65
|
"module": "esm/index.js",
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "a9f1ac35fc2dd810bae92cdaf1fc19995bee4413"
|
|
67
67
|
}
|