import {
  vcf2dstk
} from "./chunk-DKVUOBIE.js";
import {
  getsjcharts
} from "./chunk-MKAF2BHB.js";
import {
  parseheader,
  parseline
} from "./chunk-VGYTAYFK.js";
import {
  bulk_badline,
  disappear2 as disappear,
  filetypeselect,
  newpane,
  newpane3,
  renderSandboxFormDiv,
  sayerror,
  tkt
} from "./chunk-SA7APTJR.js";
import {
  invalidcoord,
  string2pos
} from "./chunk-HJ6L54YS.js";
import {
  dofetch,
  init_bulk_flag,
  parsesample
} from "./chunk-7EMWHCVW.js";
import {
  dtcloss,
  dtcnv,
  dtdel,
  dtfusionrna,
  dtitd,
  dtnloss,
  dtsnvindel,
  dtsv,
  mclasscloss,
  mclasscnvgain,
  mclasscnvloh,
  mclasscnvloss,
  mclassdel,
  mclassfusionrna,
  mclassitd,
  mclassnloss,
  mclasssv,
  mclasstester,
  validtkt
} from "./chunk-4UWS5Y3N.js";
import {
  category10_default
} from "./chunk-KSGA62R2.js";
import {
  ordinal
} from "./chunk-OAWQ6LOO.js";
import {
  select_default
} from "./chunk-I6Y4O3RR.js";

// ../shared/utils/dist/src/bulk.snv.js
function parseheader2(line, flag2) {
  const header = line.toLowerCase().split("	");
  if (header.length <= 1) return "invalid file header for snv/indel";
  const htry = (...args) => {
    for (const s of args) {
      const i2 = header.indexOf(s);
      if (i2 != -1) return i2;
    }
    return -1;
  };
  let i = htry("annovar_gene", "annovar_sj_gene", "gene", "genename", "gene_symbol", "hugo_symbol");
  if (i == -1) return "gene missing from header";
  header[i] = "gene";
  i = htry("annovar_aachange", "amino_acid_change", "annovar_sj_aachange", "aachange", "protein_change", "variant");
  if (i == -1) return "amino_acid_change missing from header";
  header[i] = "mname";
  i = htry("annovar_class", "class", "mclass", "variant_class", "variant_classification", "annovar_sj_class");
  if (i == -1) return "variant_class missing from header";
  header[i] = "class";
  i = htry("chromosome", "chr");
  if (i == -1) return "chromosome missing from header";
  header[i] = "chr";
  i = htry("wu_hg19_pos", "start", "start_position", "chr_position", "position");
  if (i == -1) return "start missing from header";
  header[i] = "pos";
  i = htry(
    "annovar_isoform",
    "mrna_accession",
    "mrna accession",
    "refseq_mrna_id",
    "annovar_sj_filter_isoform",
    "refseq",
    "isoform"
  );
  if (i == -1) return "isoform missing from header";
  header[i] = "isoform";
  i = htry("sample", "sample_name", "tumor_sample_barcode");
  if (i != -1) header[i] = "sample";
  i = htry("patient", "donor", "target_case_id");
  if (i != -1) header[i] = "patient";
  i = htry("quantitative_measurements");
  if (i != -1) header[i] = "qmset";
  i = htry("mutant_reads_in_case", "mutant_in_tumor", "tumor_readcount_alt");
  if (i != -1) header[i] = "maf_tumor_v1";
  i = htry("total_reads_in_case", "total_in_tumor", "tumor_readcount_total");
  if (i != -1) header[i] = "maf_tumor_v2";
  i = htry("mutant_reads_in_control", "mutant_in_normal", "normal_readcount_alt");
  if (i != -1) header[i] = "maf_normal_v1";
  i = htry("total_reads_in_control", "total_in_normal", "normal_readcount_total");
  if (i != -1) header[i] = "maf_normal_v2";
  i = htry("cdna_change");
  if (i != -1) header[i] = "cdna_change";
  i = htry("sampletype", "sample type", "sample_type");
  if (i != -1) header[i] = "sampletype";
  i = htry("origin");
  if (i != -1) header[i] = "origin";
  i = htry("cancer", "disease", "diagnosis");
  if (i != -1) header[i] = "disease";
  flag2.snv.header = header;
  flag2.snv.loaded = true;
  return false;
}
function parseline2(linei, line, flag2) {
  if (line == "" || line[0] == "#") return;
  const lst = line.split("	");
  const m = {};
  for (let j = 0; j < flag2.snv.header.length; j++) {
    if (lst[j] == void 0) break;
    m[flag2.snv.header[j]] = lst[j];
  }
  if (!m.gene) {
    flag2.snv.badlines.push([linei, "missing gene", lst]);
    return;
  }
  if (m.gene.toUpperCase() == "UNKNOWN") {
    flag2.snv.badlines.push([linei, "gene name is UNKNOWN", lst]);
    return;
  }
  if (!m.isoform) {
    flag2.snv.badlines.push([linei, "missing isoform", lst]);
    return;
  }
  if (!m.mname) {
    m.mname = m.cdna_change;
    if (!m.mname) {
      flag2.snv.badlines.push([linei, "missing amino acid change", lst]);
      return;
    }
  } else {
    if (m.mname.indexOf("p.") == 0) {
      m.mname = m.mname.replace(/^p\./, "");
    }
  }
  if (!m.class) {
    flag2.snv.badlines.push([linei, "missing mutation class", lst]);
    return;
  }
  let _c = flag2.mclasslabel2key[m.class.toUpperCase()];
  if (_c) {
    m.class = _c;
  } else {
    _c = mclasstester(m.class);
    if (_c) {
      m.class = _c;
    } else {
      flag2.snv.badlines.push([linei, "wrong mutation class: " + m.class, lst]);
      return;
    }
  }
  if (parsesample(m, flag2, linei, lst)) {
    return;
  }
  if (!m.chr) {
    flag2.snv.badlines.push([linei, "missing chromosome", lst]);
    return;
  }
  if (m.chr.toLowerCase().indexOf("chr") != 0) {
    m.chr = "chr" + m.chr;
  }
  if (!m.pos) {
    flag2.snv.badlines.push([linei, "missing chromosome position", lst]);
    return;
  }
  const v = Number.parseInt(m.pos);
  if (Number.isNaN(v)) {
    flag2.snv.badlines.push([linei, "invalid chromosome position", lst]);
    return;
  }
  m.pos = v - 1;
  if (m.maf_tumor_v2 != void 0 && m.maf_tumor_v1 != void 0) {
    if (m.maf_tumor_v2 == "") {
    } else {
      const v1 = Number.parseInt(m.maf_tumor_v1), v2 = Number.parseInt(m.maf_tumor_v2);
      if (Number.isNaN(v1) || Number.isNaN(v2)) {
        flag2.snv.badlines.push([linei, "invalid maf_tumor mutant and/or total read count", lst]);
        return;
      }
      m.maf_tumor = { f: v1 / v2, v1, v2 };
    }
    delete m.maf_tumor_v1;
    delete m.maf_tumor_v2;
  }
  if (m.maf_normal_v1 != void 0 && m.maf_normal_v2 != void 0) {
    if (m.maf_normal_v2 == "") {
    } else {
      const v1 = Number.parseInt(m.maf_normal_v1), v2 = Number.parseInt(m.maf_normal_v2);
      if (Number.isNaN(v1) || Number.isNaN(v2)) {
        flag2.snv.badlines.push([linei, "invalid maf_normal mutant and/or total read count", lst]);
        return;
      }
      m.maf_normal = { f: v1 / v2, v1, v2 };
    }
    delete m.maf_normal_v1;
    delete m.maf_normal_v2;
  }
  flag2.good++;
  if (m.class == "M") {
    flag2.snv.missense++;
  } else if (m.class == "S") {
    flag2.snv.silent++;
  }
  const n = flag2.geneToUpper ? m.gene.toUpperCase() : m.gene;
  if (!flag2.data[n]) {
    flag2.data[n] = [];
  }
  m.dt = dtsnvindel;
  flag2.data[n].push(m);
}

// ../shared/utils/dist/src/bulk.svjson.js
function parseheader3(line) {
  const header = line.toLowerCase().split("	");
  if (header.length <= 1) return "invalid file header for svjson";
  const htry = (...lst) => {
    for (const a of lst) {
      const j = header.indexOf(a);
      if (j != -1) return j;
    }
    return -1;
  };
  let i = htry("sample");
  if (i != -1) header[i] = "sample";
  i = htry("sampletype");
  if (i != -1) header[i] = "sampletype";
  i = htry("patient");
  if (i != -1) header[i] = "patient";
  i = htry("json", "jsontext");
  if (i == -1) return ["json missing from header"];
  header[i] = "jsontext";
  return [null, header];
}
function parseline3(i, line, flag2, header) {
  if (line == "" || line[0] == "#") return;
  const lst = line.split("	");
  const m = {};
  const badlines = flag2.svjson.badlines;
  for (let j = 0; j < header.length; j++) {
    m[header[j]] = lst[j];
  }
  if (!m.jsontext) {
    badlines.push([i, "missing jsontext", lst]);
    return;
  }
  if (parsesample(m, flag2, i, lst)) {
    return;
  }
  let json;
  try {
    json = JSON.parse(m.jsontext);
  } catch (_) {
    badlines.push([i, "invalid JSON text", lst]);
    return;
  }
  if (Array.isArray(json)) {
    for (const pair of json) {
      if (pair.a && pair.a.name && pair.a.isoform) {
        flag2.good++;
        const m2 = {
          dt: dtfusionrna,
          class: mclassfusionrna,
          isoform: pair.a.isoform,
          mname: pair.b.name
        };
        for (const k in m) {
          if (k != "jsontext") m2[k] = m[k];
        }
        m2.pairlst = duplicate(json);
        const n = pair.a.name.toUpperCase();
        if (!flag2.data[n]) {
          flag2.data[n] = [];
        }
        flag2.data[n].push(m2);
      }
      if (pair.b && pair.b.name && pair.b.isoform) {
        flag2.good++;
        const m2 = {
          dt: dtfusionrna,
          class: mclassfusionrna,
          isoform: pair.b.isoform,
          mname: pair.a.name
        };
        for (const k in m) {
          if (k != "jsontext") m2[k] = m[k];
        }
        m2.pairlst = duplicate(json);
        const n = pair.b.name.toUpperCase();
        if (!flag2.data[n]) {
          flag2.data[n] = [];
        }
        flag2.data[n].push(m2);
      }
    }
  } else {
    json.dt = json.typecode;
    delete json.typecode;
    switch (json.dt) {
      case dtitd:
        json.class = mclassitd;
        json.mname = "ITD";
        break;
      case dtnloss:
        json.class = mclassnloss;
        json.mname = "N-loss";
        break;
      case dtcloss:
        json.class = mclasscloss;
        json.mname = "C-loss";
        break;
      case dtdel:
        json.class = mclassdel;
        json.mname = "Del";
        break;
      case dtsv:
        json.class = mclasssv;
        json.mname = "SV";
        break;
      default:
        badlines.push([i, "unknown datatype", lst]);
        return;
    }
    if (!json.gene) {
      badlines.push([i, "json.gene missing", lst]);
      return;
    }
    flag2.good++;
    for (const k in m) {
      if (k != "jsontext") {
        json[k] = m[k];
      }
    }
    const n = flag2.geneToUpper ? json.gene.toUpperCase() : json.gene.toUpperCase();
    if (!flag2.data[n]) {
      flag2.data[n] = [];
    }
    flag2.data[n].push(json);
  }
}
function duplicate(lst) {
  const d = [];
  for (const pair of lst) {
    const p = { a: {}, b: {} };
    for (const k in pair) {
      if (k != "a" && k != "b") p[k] = pair[k];
    }
    for (const k in pair.a) {
      p.a[k] = pair.a[k];
    }
    for (const k in pair.b) {
      p.b[k] = pair.b[k];
    }
    d.push(p);
  }
  return d;
}

// ../shared/utils/dist/src/bulk.cnv.js
function parseheader4(line, flag2) {
  const header = line.toLowerCase().split("	");
  if (header.length <= 1) return "invalid file header for CNV";
  const htry = (...lst) => {
    for (const i2 of lst) {
      const j = header.indexOf(i2);
      if (j != -1) return j;
    }
    return -1;
  };
  let i = htry("gene");
  if (i == -1) return "gene missing from header";
  header[i] = "gene";
  i = htry("cnv");
  if (i == -1) return "CNV missing from header";
  header[i] = "cnv";
  i = htry("sample", "sample_name", "tumor_sample_barcode");
  if (i != -1) header[i] = "sample";
  i = htry("patient", "donor", "target_case_id");
  if (i != -1) header[i] = "patient";
  i = htry("disease");
  if (i != -1) header[i] = "disease";
  i = htry("origin");
  if (i != -1) header[i] = "origin";
  i = htry("sampletype", "sample type", "sample_type");
  if (i != -1) header[i] = "sampletype";
  flag2.cnv.header = header;
  flag2.cnv.loaded = true;
  return false;
}
function parseline4(i, line, flag2) {
  if (line == "" || line[0] == "#") return;
  const lst = line.split("	");
  const m = {};
  for (let j = 0; j < flag2.cnv.header.length; j++) {
    m[flag2.cnv.header[j]] = lst[j];
  }
  if (!m.gene) {
    flag2.cnv.badlines.push([i, "missing gene", lst]);
    return;
  }
  if (!m.cnv) {
    flag2.cnv.badlines.push([i, "missing cnv value", lst]);
    return;
  }
  const value = m.cnv.toLowerCase();
  switch (value) {
    case "amplification":
    case "gain":
      m.class = mclasscnvgain;
      break;
    case "deletion":
    case "loss":
      m.class = mclasscnvloss;
      break;
    case "loh":
      m.class = mclasscnvloh;
      break;
    default:
      flag2.cnv.badlines.push([i, "invalid cnv value: " + m.cnv, lst]);
      m.class = null;
  }
  if (!m.class) {
    return;
  }
  if (parsesample(m, flag2, i, lst)) {
    return;
  }
  m.dt = dtcnv;
  flag2.good++;
  const n = flag2.geneToUpper ? m.gene.toUpperCase() : m.gene;
  if (!(n in flag2.data)) {
    flag2.data[n] = [];
  }
  flag2.data[n].push(m);
}

// ../shared/utils/dist/src/bulk.itd.js
function parseheader5(line, flag2) {
  const header = line.toLowerCase().split("	");
  if (header.length <= 1) return "invalid header line for ITD";
  const htry = (...lst) => {
    for (const i2 of lst) {
      const j = header.indexOf(i2);
      if (j != -1) return j;
    }
    return -1;
  };
  let i = htry("gene");
  if (i == -1) return "gene missing from header";
  header[i] = "gene";
  i = htry(
    "annovar_isoform",
    "mrna_accession",
    "mrna accession",
    "refseq_mrna_id",
    "annovar_sj_filter_isoform",
    "refseq",
    "isoform"
  );
  if (i == -1) return "isoform missing from header";
  header[i] = "isoform";
  i = htry("rnaposition");
  if (i != -1) {
    header[i] = "rnaposition";
    i = htry("rnaduplength");
    if (i == -1) return "rnaduplength is required when rnaposition is present";
    header[i] = "rnaduplength";
  }
  i = htry("chromosome", "chr");
  if (i != -1) {
    header[i] = "chr";
    i = htry("chr_start");
    if (i == -1) return "chr_start is required when chr is present";
    header[i] = "chrpos1";
    i = htry("chr_stop");
    if (i == -1) return "chr_stop is required when chr is present";
    header[i] = "chrpos2";
  }
  i = htry("sample", "sample_name", "tumor_sample_barcode");
  if (i != -1) header[i] = "sample";
  i = htry("patient", "donor", "target_case_id");
  if (i != -1) header[i] = "patient";
  i = htry("disease");
  if (i != -1) header[i] = "disease";
  i = htry("origin");
  if (i != -1) header[i] = "origin";
  i = htry("sampletype", "sample type", "sample_type");
  if (i != -1) header[i] = "sampletype";
  flag2.itd.header = header;
  flag2.itd.loaded = true;
  return false;
}
function parseline5(i, line, flag2) {
  if (line == "" || line[0] == "#") return;
  const lst = line.split("	");
  const m = {};
  for (let j = 0; j < flag2.itd.header.length; j++) {
    if (lst[j] == void 0) break;
    m[flag2.itd.header[j]] = lst[j];
  }
  if (!m.gene) {
    flag2.itd.badlines.push([i, "missing gene", lst]);
    return;
  }
  if (m.rnaposition) {
    let v = Number.parseInt(m.rnaposition);
    if (Number.isNaN(v) || v < 0) {
      flag2.itd.badlines.push([i, "invalid rnaPosition value", lst]);
      return;
    }
    m.rnaposition = v;
    if (!m.rnaduplength) {
      flag2.itd.badlines.push([i, "missing rnaDuplength value", lst]);
      return;
    }
    v = Number.parseInt(m.rnaduplength);
    if (Number.isNaN(v) || v < 0) {
      flag2.itd.badlines.push([i, "invalid rnaDuplength value", lst]);
      return;
    }
    m.rnaduplength = v;
  }
  if (m.chr) {
    let v = Number.parseInt(m.chrpos1);
    if (Number.isNaN(v) || v < 0) {
      flag2.itd.badlines.push([i, "invalid chr_start value", lst]);
      return;
    }
    m.chrpos1 = v;
    v = Number.parseInt(m.chrpos2);
    if (Number.isNaN(v) || v < 0) {
      flag2.itd.badlines.push([i, "invalid chr_stop value", lst]);
      return;
    }
    m.chrpos2 = v;
  }
  if (parsesample(m, flag2, i, lst)) {
    return;
  }
  m.dt = dtitd;
  m.class = mclassitd;
  m.mname = "ITD";
  flag2.good++;
  const n = flag2.geneToUpper ? m.gene.toUpperCase() : m.gene;
  if (!(n in flag2.data)) {
    flag2.data[n] = [];
  }
  flag2.data[n].push(m);
}

// ../shared/utils/dist/src/bulk.del.js
function parseheader6(line, flag2) {
  const header = line.toLowerCase().split("	");
  if (header.length <= 1) return "invalid header line for intragenic deletion";
  const htry = (...lst) => {
    for (const i2 of lst) {
      const j = header.indexOf(i2);
      if (j != -1) return j;
    }
    return -1;
  };
  let i = htry("gene");
  if (i == -1) return "gene missing from header";
  header[i] = "gene";
  i = htry(
    "annovar_isoform",
    "mrna_accession",
    "mrna accession",
    "refseq_mrna_id",
    "annovar_sj_filter_isoform",
    "refseq",
    "isoform"
  );
  if (i == -1) return "isoform missing from header";
  header[i] = "isoform";
  i = htry("rnaposition");
  if (i != -1) {
    header[i] = "rnaposition";
    i = htry("rnadellength");
    if (i == -1) return "rnadellength is required when rnaPosition is used";
    header[i] = "rnadellength";
  }
  i = htry("chromosome", "chr");
  if (i != -1) {
    header[i] = "chr";
    i = htry("chr_start");
    if (i == -1) return "chr_start is required when chr is used";
    header[i] = "chrpos1";
    i = htry("chr_stop");
    if (i == -1) return "chr_stop is required when chr is used";
    header[i] = "chrpos2";
  }
  i = htry("sample", "sample_name", "tumor_sample_barcode");
  if (i != -1) header[i] = "sample";
  i = htry("patient", "donor", "target_case_id");
  if (i != -1) header[i] = "patient";
  i = htry("disease");
  if (i != -1) header[i] = "disease";
  i = htry("origin");
  if (i != -1) header[i] = "origin";
  i = htry("sampletype", "sample type", "sample_type");
  if (i != -1) header[i] = "sampletype";
  flag2.del.header = header;
  flag2.del.loaded = true;
  return false;
}
function parseline6(i, line, flag2) {
  if (line == "" || line[0] == "#") return;
  const lst = line.split("	");
  const m = {};
  for (let j = 0; j < flag2.del.header.length; j++) {
    if (lst[j] == void 0) break;
    m[flag2.del.header[j]] = lst[j];
  }
  if (!m.gene) {
    flag2.del.badlines.push([i, "missing gene", lst]);
    return;
  }
  if (m.rnaposition) {
    let v = Number.parseInt(m.rnaposition);
    if (Number.isNaN(v) || v < 0) {
      flag2.del.badlines.push([i, "invalid rnaPosition value", lst]);
      return;
    }
    m.rnaposition = v;
    if (!m.rnadellength) {
      flag2.del.badlines.push([i, "missing rnaDellength value", lst]);
      return;
    }
    v = Number.parseInt(m.rnadellength);
    if (Number.isNaN(v) || v < 0) {
      flag2.del.badlines.push([i, "invalid rnaDellength value", lst]);
      return;
    }
    m.rnadellength = v;
  }
  if (m.chr) {
    let v = Number.parseInt(m.chrpos1);
    if (Number.isNaN(v) || v < 0) {
      flag2.del.badlines.push([i, "invalid chr_start value", lst]);
      return;
    }
    m.chrpos1 = v;
    v = Number.parseInt(m.chrpos2);
    if (Number.isNaN(v) || v < 0) {
      flag2.del.badlines.push([i, "invalid chr_stop value", lst]);
      return;
    }
    m.chrpos2 = v;
  }
  if (parsesample(m, flag2, i, lst)) {
    return;
  }
  m.dt = dtdel;
  m.class = mclassdel;
  m.mname = "DEL";
  flag2.good++;
  const n = flag2.geneToUpper ? m.gene.toUpperCase() : m.gene;
  if (!(n in flag2.data)) {
    flag2.data[n] = [];
  }
  flag2.data[n].push(m);
}

// ../shared/utils/dist/src/bulk.trunc.js
function parseheader7(line, flag2) {
  const header = line.toLowerCase().split("	");
  if (header.length <= 1) return "invalid header line for truncation";
  const htry = (...lst) => {
    for (const e of lst) {
      const j = header.indexOf(e);
      if (j != -1) return j;
    }
    return -1;
  };
  let i = htry("gene");
  if (i == -1) return "gene missing from header";
  header[i] = "gene";
  i = htry(
    "annovar_isoform",
    "mrna_accession",
    "mrna accession",
    "refseq_mrna_id",
    "annovar_sj_filter_isoform",
    "refseq",
    "isoform"
  );
  if (i == -1) return "isoform missing from header";
  header[i] = "isoform";
  let hasrnapos = false;
  i = htry("rnaposition");
  if (i != -1) {
    header[i] = "rnaposition";
    hasrnapos = true;
  }
  i = htry("losstype");
  if (i == -1) return "lossType missing from header";
  header[i] = "losstype";
  let hasgenomic = false;
  i = htry("chromosome", "chr");
  if (i != -1) {
    header[i] = "chr";
    i = htry("start", "start_position", "wu_hg19_pos", "chr_position", "position");
    if (i == -1) {
      return "genomic position missing from header";
    }
    header[i] = "pos";
    hasgenomic = true;
  }
  if (!hasrnapos && !hasgenomic) {
    return "neither rnaposition nor genomic position is given";
  }
  i = htry("sample", "sample_name", "tumor_sample_barcode");
  if (i != -1) header[i] = "sample";
  i = htry("patient", "donor", "target_case_id");
  if (i != -1) header[i] = "patient";
  i = htry("disease");
  if (i != -1) header[i] = "disease";
  i = htry("origin");
  if (i != -1) header[i] = "origin";
  i = htry("sampletype", "sample type", "sample_type");
  if (i != -1) header[i] = "sampletype";
  flag2.truncation.header = header;
  flag2.truncation.loaded = true;
  return false;
}
function parseline7(i, line, flag2) {
  if (line == "" || line[0] == "#") return;
  const lst = line.split("	");
  const m = {};
  for (let j = 0; j < flag2.truncation.header.length; j++) {
    m[flag2.truncation.header[j]] = lst[j];
  }
  if (!m.gene) {
    flag2.truncation.badlines.push([i, "missing gene", lst]);
    return;
  }
  if (m.rnaposition) {
    const v = Number.parseInt(m.rnaposition);
    if (Number.isNaN(v) || v < 0) {
      flag2.truncation.badlines.push([i, "invalid rnaPosition value", lst]);
      return;
    }
    m.rnaposition = v;
  }
  if (m.pos) {
    const v = Number.parseInt(m.pos);
    if (Number.isNaN(v) || v < 0) {
      flag2.truncation.badlines.push([i, "invalid genomic position", lst]);
      return;
    }
    m.pos = v;
  }
  if (!m.losstype) {
    flag2.truncation.badlines.push([i, "missing lossType value", lst]);
    return;
  }
  if (m.losstype != "n" && m.losstype != "c") {
    flag2.truncation.badlines.push([i, 'lossType value not "n" or "c"', lst]);
    return;
  }
  if (parsesample(m, flag2, i, lst)) {
    return;
  }
  if (m.losstype == "n") {
    m.dt = dtnloss;
    m.class = mclassnloss;
    m.mname = "N-loss";
  } else {
    m.dt = dtcloss;
    m.class = mclasscloss;
    m.mname = "C-loss";
  }
  flag2.good++;
  const n = flag2.geneToUpper ? m.gene.toUpperCase() : m.gene;
  if (!(n in flag2.data)) {
    flag2.data[n] = [];
  }
  flag2.data[n].push(m);
}

// src/bulk.project.js
var schemaNames = ["heatmapJSON", "piebarJSON", "survivalJSON", "discoJSON", "riverJSON"];
var typeIndex = {
  snvindel: 0,
  si: 0,
  sv: 1,
  fusion: 2,
  itd: 3,
  deletion: 4,
  truncation: 5,
  cnv: 6
};
var urlProjectLoaded = false;
var ProjectHandler = class {
  /*
  		Create a handler for multiple uploaded or fetched
  		files in a project
  
  		bt = {
  			flag: closured flag inside bulkui.bulkui,
  			bulkin: bulkui.bulkin,
  			content2flag: bulkui.content2flag,
  			flag2tp: closured flat2tp,
  			filediv: (optional) d3-wrapped container for file-input
  		}
  	*/
  constructor(bt) {
    this.bt = bt;
    this.err = this.errHandler();
    if (!urlProjectLoaded) {
      const params = getParams();
      if (params.project) {
        this.getData(params.project);
        urlProjectLoaded = true;
      }
    }
    if (bt.filediv) {
      this.projectByInput(bt.filediv);
    }
  }
  /*
  		Process data files sequentially for rendering
  		into a TP div
  
  		data = {
  			schemas: object {
  				heatmapJSON (optional),
  				piebarJSON (optional),
  				survivalJSON (optional)
  			},
  			files: [] array of {
  				name: string
  				typeL one of the typeIndex values 
  				content: string
  			}
  		}
  	*/
  processData(data) {
    const file = data.files.pop();
    const i = data.expectedFileNames.indexOf(file.name);
    if (i == -1) {
      if (data.files.length)
        setTimeout(() => {
          this.processData(data);
        }, 1);
      return;
    }
    data.expectedFileNames.splice(i, 1);
    this.cohort = {
      name: "project",
      genome: this.bt.genomes[this.bt.gselect.options[this.bt.gselect.selectedIndex].innerHTML]
    };
    if (!this.flag) {
      this.flag = this.bt.init_bulk_flag(this.cohort.genome);
    }
    const error = this.bt.content2flag(file.content, file.type, this.flag);
    if (error) {
      this.err(error);
      this.processData(data);
    } else if (!data.files.length) {
      if (data.expectedFileNames.length) {
        this.err('These referenced files were not found: "' + data.expectedFileNames.join('", "') + '".');
      }
      this.bt.flag2tp(this.flag, { name: "project" }, Object.assign(this.cohort, data.schema), this.ds);
      return;
    } else {
      if (!this.ds) {
        for (const k in this.cohort.dsset) {
          this.ds = this.cohort.dsset[k];
          break;
        }
      }
      const error1 = this.bt.bulkin(
        {
          flag: this.flag,
          cohort: this.cohort,
          flag2thisds: this.ds,
          filename: "project"
        },
        () => {
          this.processData(data);
        }
      );
      if (error1) {
        this.err("Error with " + file.name + ": " + error1);
        return;
      }
      if (this.flag.good === 0) {
        this.err(file.name + ": no data loaded");
        return;
      }
    }
  }
  getData(project) {
    const [projectname, _refname] = project.split("/");
    const refname = _refname && _refname.trim() ? _refname.trim() : "ref.txt";
    this.gettext("/data/projects/" + projectname + "/" + refname, (text) => {
      const fileNameToType = {};
      const nameToSchemaType = {};
      const data = { schema: {}, files: [], expectedFileNames: [] };
      let schemaFileName = "";
      let numProcessedFiles = 0;
      let numFiles = 0;
      text.trim().split("\n").forEach((line) => {
        const [type, filename] = line.trim().split("	");
        if (schemaNames.includes(type)) {
          nameToSchemaType[filename] = type;
          numFiles += 1;
        } else if (!typeIndex[type] && typeIndex[type] !== 0) {
          this.err("Unrecognized type " + type + " for file " + filename + " in reference.txt.");
        } else {
          fileNameToType[filename] = typeIndex[type];
          numFiles += 1;
        }
      });
      data.expectedFileNames = Object.keys(fileNameToType);
      const tracker = this.getTracker(numFiles, () => this.processData(data));
      Object.keys(nameToSchemaType).forEach((filename) => {
        this.getjson("/data/projects/" + projectname + "/" + filename, (json) => {
          data.schema[nameToSchemaType[filename]] = json;
          tracker();
        });
      });
      Object.keys(fileNameToType).forEach((filename) => {
        this.gettext("/data/projects/" + projectname + "/" + filename, (text2) => {
          data.files.push({
            name: filename,
            type: fileNameToType[filename],
            content: text2
          });
          tracker();
        });
      });
    });
  }
  gettext(url, callback) {
    fetch(url).then((response) => {
      if (response.ok) return response.text();
      else this.err("File request error: " + url);
    }).then(callback).catch((error) => this.err("File request error: " + url + " " + error));
  }
  getjson(url, callback) {
    fetch(url).then((response) => {
      if (response.ok) return response.json();
      else this.err("Network error for " + url);
    }).then(callback).catch((error) => this.err("file request error: " + url + " " + error));
  }
  getTracker(numFiles, callback) {
    let numProcessedFiles = 0;
    return function tracker() {
      numProcessedFiles += 1;
      if (numProcessedFiles == numFiles) {
        callback();
      }
    };
  }
  projectByInput(filediv) {
    this.tp = null;
    const advancedDiv = filediv.append("div");
    advancedDiv.append("span").html("Project: reference &nbsp;");
    this.refNameInput = advancedDiv.append("input").attr("type", "text").property("value", "ref.txt").style("margin-right", "20px").style("padding-left", "7px");
    const buttlabel = advancedDiv.append("label").attr("for", "sja-pp-bulk-ui-project-btn").attr("class", "sja_btn").style("padding", "3px 5px").html("Choose folder");
    const butt = advancedDiv.append("input").attr("type", "file").attr("id", "sja-pp-bulk-ui-project-btn").property("multiple", true).property("webkitdirectory", true).property("directory", true).on("change", (event) => this.readFiles(event));
    advancedDiv.append("div").style("margin", "10px 10px 10px 0").html(`<a href="https://docs.google.com/document/d/1wlfGzyhxFYtWu9Fyf3FK7pgvS3rVb9_vrfYUBUOUrw4/edit?usp=sharing" target="new">Project user guide</a> | 
			<a href='https://proteinpaint.stjude.org/ppdemo/projects/target-tall-project/ref.txt' target=_blank>Example project reference file</a>`);
    advancedDiv.append("div").style("margin", "20px").style("width", "100%").html("-- OR --");
  }
  /* to be used as a file input (FileList) handler */
  readFiles(event) {
    const self = this;
    const refFileName = self.refNameInput.property("value");
    const files = Array.from(event.target.files);
    const ref = files.filter((f) => f.name == refFileName)[0];
    if (!ref) {
      self.err("Missing reference file='" + refFileName + "'.");
      return;
    }
    const fileNameToType = {};
    const nameToSchemaType = {};
    const data = { schema: {}, files: [], expectedFileNames: [] };
    const reader = new FileReader();
    let schemaFileName = "";
    let numProcessedFiles = 0;
    reader.onload = (event2) => {
      event2.target.result.trim().split("\n").forEach((line) => {
        const [type, filename] = line.trim().split("	");
        if (schemaNames.includes(type)) {
          nameToSchemaType[filename] = type;
        } else if (!typeIndex[type] && typeIndex[type] !== 0) {
          self.err("Unrecognized type " + type + " for file " + filename + " in reference.txt.");
        } else {
          fileNameToType[filename] = typeIndex[type];
        }
      });
      data.expectedFileNames = Object.keys(fileNameToType);
      const schemaFiles = files.filter((file) => file.name in nameToSchemaType);
      let numProcessedSchemas = 0;
      if (!schemaFiles.length) {
        files.forEach(processFile);
      } else {
        schemaFiles.forEach((file) => {
          const reader2 = new FileReader();
          reader2.onload = (event3) => {
            const schema = JSON.parse(event3.target.result);
            numProcessedSchemas += 1;
            if (!schema) {
              self.err('Unable to parse schema file="' + file.name + '".');
            } else {
              data.schema[nameToSchemaType[file.name]] = schema;
            }
            if (numProcessedSchemas == schemaFiles.length) {
              files.forEach(processFile);
            }
          };
          reader2.onerror = () => {
            self.err("Error reading schema.txt.");
          };
          reader2.readAsText(file, "utf8");
        });
      }
      function processFile(file) {
        if (!data.expectedFileNames.includes(file.name)) {
          numProcessedFiles += 1;
          return;
        }
        if (!file) {
          self.err("Error reading file.");
          numProcessedFiles += 1;
          return;
        }
        if (file.size == 0) {
          self.err("Wrong file: " + file.name);
          numProcessedFiles += 1;
          return;
        }
        if (!fileNameToType[file.name] && fileNameToType[file.name] !== 0 && file.name != schemaFileName) {
          self.err("Missing or invalid type assigned to file " + file.name + ".");
          numProcessedFiles += 1;
          return;
        }
        const reader2 = new FileReader();
        reader2.onload = (event3) => {
          numProcessedFiles += 1;
          data.files.push({
            name: file.name,
            type: fileNameToType[file.name],
            content: event3.target.result
          });
          if (numProcessedFiles == files.length) {
            self.processData(data);
          }
        };
        reader2.onerror = () => {
          numProcessedFiles += 1;
          self.err("Error reading file " + file.name);
          if (numProcessedFiles == files.length) {
            self.processData(data);
          }
        };
        reader2.readAsText(file, "utf8");
      }
    };
    reader.onerror = () => {
      self.err("Error reading reference.txt.");
    };
    reader.readAsText(ref, "utf8");
  }
  // function to track and display accumulated error messages
  errHandler() {
    const errdiv = select_default("body").append("div");
    let mssg = "";
    return function(m) {
      if (!m) return;
      sayerror(errdiv, m);
    };
  }
};
function getParams() {
  const params = {};
  window.location.search.substr(1).split("&").forEach((kv) => {
    const [key, value] = kv.split("=");
    params[key] = value;
  });
  return params;
}

// src/bulk.ui.js
function bulkui(x, y, genomes, hostURL, holder, header) {
  let pane, inputdiv, gselect, filediv, saydiv, visualdiv;
  if (holder !== void 0) [inputdiv, gselect, filediv, saydiv, visualdiv] = renderSandboxFormDiv(holder, genomes);
  else {
    ;
    [pane, inputdiv, gselect, filediv, saydiv, visualdiv] = newpane3(x, y, genomes);
    pane.header.text("Load mutation from text files");
  }
  inputdiv.append("div").style("margin", "20px 0px").style("color", "#858585").html(`
	<p>Choose one file and upload to initiate the display panel.<br>From there you can add additional files.</p>
	<div>Supported data types:</div>
	<ul>
	  <li>SNV and indel</li>
	  <ul>
	    <li><a href=https://drive.google.com/open?id=1OJ9aXq2_-a3BfIQdKLYCYzrJRTpu4_9i3gephTY-Z38 target=_blank>Format</a>,
	        <a href=https://proteinpaint.stjude.org/ppdemo/hg19/heatmap/exampleFiles/example.snvindel.txt target=_blank>example file</a></li>
	  </ul>
	  <li>SV or fusion transcript</li>
	  <ul>
	    <li><a href=https://drive.google.com/open?id=1klDZ0MHVkQTW2-lCu_AvpRE4_FcbhdB-yI17wNdPaOM target=_blank>Tabular format</a>,
	        <a href=https://proteinpaint.stjude.org/ppdemo/hg19/heatmap/exampleFiles/example.svfusion.txt target=_blank>example file</a>
		</li>
		<li>JSON-format, to come</li>
	  </ul>
	  <li>CNV, gene-level</li>
	  <ul>
	    <li><a href=https://drive.google.com/open?id=1WHptqOWNf96V0bYEDpj-EsKZGYnbBNc9aQIrhzdEJaU target=_blank>Format</a>, 
	        <a href=https://proteinpaint.stjude.org/ppdemo/hg19/heatmap/exampleFiles/example.cnv.txt target=_blank>example file</a>
		</li>
	  </ul>
	  <li>ITD</li>
	  <ul>
	  	<li>Internal tandem duplication, in-frame</li>
	    <li><a href=https://drive.google.com/open?id=1Bh9awBsraoHbV8iWXv_3oDeXMsjIAHaOKHr973IJyZc target=_blank>Format</a>, 
	        <a href=https://proteinpaint.stjude.org/ppdemo/hg19/heatmap/exampleFiles/example.itd.txt target=_blank>example file</a>
		</li>
	  </ul>
	  <li>Intragenic deletion, in-frame</li>
	  <ul>
	    <li><a href=https://drive.google.com/open?id=1tWbf3rg3BmVIZPGGPk023P0aBkDw_ry5XuZLGyGodyg target=_blank>Format</a>, 
	        <a href=https://proteinpaint.stjude.org/ppdemo/hg19/heatmap/exampleFiles/example.deletion.txt target=_blank>example file</a>
		</li>
	  </ul>
	  <li>Truncation</li>
	  <ul>
	  	<li>Either N-terminus loss or C-terminus loss</li>
	    <li><a href=https://drive.google.com/open?id=1P1g-Y8r30pSKfan1BhYZcsUtSk7wRb4plaO1S-JCJr4 target=_blank>Format</a>, 
	        <a href=https://proteinpaint.stjude.org/ppdemo/hg19/heatmap/exampleFiles/example.truncation.txt target=_blank>example file</a>
		</li>
	  </ul>
	</ul>`);
  const fileui = () => {
    filediv.selectAll("*").remove();
    new ProjectHandler({
      bulkin,
      genomes,
      gselect,
      content2flag,
      flag2tp,
      filediv,
      init_bulk_flag
    });
    filediv.append("span").html("Select data type&nbsp;");
    const typeselect = filetypeselect(filediv).style("margin-right", "20px");
    const butt = filediv.append("input").attr("type", "file").on("change", (event) => {
      const flag2 = init_bulk_flag(genomes[gselect.options[gselect.selectedIndex].innerHTML]);
      flag2.geneToUpper = geneToUpper.property("checked");
      saydiv.text("");
      const file = event.target.files[0];
      if (!file) {
        fileui();
        return;
      }
      if (file.size == 0) {
        saydiv.text("Wrong file: " + file.name);
        fileui();
        return;
      }
      const reader = new FileReader();
      reader.onload = (event2) => {
        const error = content2flag(event2.target.result, typeselect.node().selectedIndex, flag2);
        if (error) {
          saydiv.text("Error: " + error);
          fileui();
          return;
        }
        flag2tp(flag2, file);
      };
      reader.onerror = function() {
        saydiv.text("Error reading file " + file.name);
        fileui();
        return;
      };
      saydiv.text("Parsing file " + file.name + " ...");
      reader.readAsText(file, "utf8");
    });
    setTimeout(() => butt.node().focus(), 1100);
  };
  fileui();
  filediv.append("span").html("<br/>Convert gene name to uppercase &nbsp;");
  const geneToUpper = filediv.append("span").append("input").attr("type", "checkbox").property("checked", true);
  function flag2tp(flag2, file, _cohort = null, ds = null) {
    if (typeof flag2 == "string") {
      saydiv.text(flag2);
      fileui();
      return;
    }
    saydiv.text("");
    fileui();
    const cohort = _cohort ? _cohort : Object.assign({
      genome: flag2.genome,
      name: file.name
    });
    const err2 = bulkin({
      flag: flag2,
      filename: file.name,
      cohort,
      flag2thisds: ds
    });
    if (err2) {
      saydiv.text("Error with " + file.name + ": " + err2);
      return;
    }
    if (flag2.good == 0) {
      saydiv.text("No mutations can be loaded");
      return;
    }
    let visual_holder;
    if (pane) {
      disappear(pane.pane);
      const pane2 = newpane({ x: 100, y: 100, toshrink: true });
      pane2.header.html('<span style="opacity:.5">FILE</span> ' + file.name);
      visual_holder = pane2.body;
    }
    if (holder !== void 0) {
      visual_holder = visualdiv.append("div").html('<span style="opacity:.5">FILE</span> ' + file.name);
    }
    inputdiv.selectAll("*").remove();
    import("./tp.ui-T7FVMTGQ.js").then((tpui) => {
      tpui.default(cohort, visual_holder, hostURL);
    });
    return cohort;
  }
  return function content2flag2tp(file, type) {
    const error = content2flag(file.content, type, flag);
    if (error) {
      saydiv.text("Error: " + error);
      fileui();
      return;
    }
    flag2tp(flag, file);
  };
}
function content2flag(text, type, flag2) {
  if (!flag2) return "should not happen!";
  let err2;
  switch (type) {
    case 0:
      err2 = parse_snvindel(text, flag2);
      if (err2) return err2;
      break;
    case 1:
      err2 = parse_sv(text, flag2, true);
      if (err2) return err2;
      break;
    case 2:
      err2 = parse_sv(text, flag2, false);
      if (err2) return err2;
      break;
    case 3:
      err2 = parse_itd(text, flag2);
      if (err2) return err2;
      break;
    case 4:
      err2 = parse_del(text, flag2);
      if (err2) return err2;
      break;
    case 5:
      err2 = parse_trunc(text, flag2);
      if (err2) return err2;
      break;
    case 6:
      err2 = parse_cnv(text, flag2);
      if (err2) return err2;
      break;
    default:
      return "unknown option array index from file type <select>: " + type;
  }
}
function bulkin(p, callback = null) {
  const flag2 = p.flag;
  const cohort = p.cohort;
  if (!cohort.p2st) {
    cohort.p2st = {};
  }
  if (!cohort.dsset) {
    cohort.dsset = {};
  }
  if (!cohort.assaylst) {
    cohort.assaylst = [];
  }
  if (flag2.variantgene) {
    if (cohort.variantgene) {
      return "variantgene already set for this cohort";
    }
    cohort.variantgene = flag2.variantgene;
  }
  if (flag2.snv.badlines.length > 0) {
    bulk_badline(flag2.snv.header, flag2.snv.badlines);
  }
  if (flag2.fusion.badlines.length > 0) {
    bulk_badline(flag2.fusion.header, flag2.fusion.badlines);
  }
  if (flag2.sv.badlines.length > 0) {
    bulk_badline(flag2.sv.header, flag2.sv.badlines);
  }
  if (flag2.cnv.badlines.length > 0) {
    bulk_badline(flag2.cnv.header, flag2.cnv.badlines);
  }
  if (flag2.itd.badlines.length > 0) {
    bulk_badline(flag2.itd.header, flag2.itd.badlines);
  }
  if (flag2.del.badlines.length > 0) {
    bulk_badline(flag2.del.header, flag2.del.badlines);
  }
  if (flag2.truncation.badlines.length > 0) {
    bulk_badline(flag2.truncation.header, flag2.truncation.badlines);
  }
  if (flag2.good == 0) {
    return false;
  }
  const tmp = {};
  let hastumormaf = false;
  if (flag2.snv.loaded) {
    for (const i of flag2.snv.header) {
      tmp[i] = 1;
    }
    if ("maf_tumor_v1" in tmp && "maf_tumor_v2" in tmp) {
      hastumormaf = true;
    }
  }
  if (flag2.cnv.loaded) {
    for (const i of flag2.cnv.header) {
      tmp[i] = 1;
    }
  }
  if (flag2.fusion.loaded) {
    for (const i of flag2.fusion.header) {
      tmp[i] = 1;
    }
  }
  if (flag2.sv.loaded) {
    for (const i of flag2.sv.header) {
      tmp[i] = 1;
    }
  }
  if (flag2.itd.loaded) {
    for (const i of flag2.itd.header) {
      tmp[i] = 1;
    }
  }
  if (flag2.del.loaded) {
    for (const i of flag2.del.header) {
      tmp[i] = 1;
    }
  }
  if (flag2.truncation.loaded) {
    for (const i of flag2.truncation.header) {
      tmp[i] = 1;
    }
  }
  const hassample = "sample" in tmp || "patient" in tmp;
  const hasdisease = "disease" in tmp;
  const hasst = "sampletype" in tmp;
  let dsc;
  if (p.flag2thisds) {
    dsc = p.flag2thisds;
    if (hassample && !dsc.hassample) {
      return '"sample" column found in new data but not in existing data';
    }
    if (!hassample && dsc.hassample) {
      return '"sample" column found in existing data but not in new data';
    }
    if (hasdisease && !dsc.hasdisease) {
      return '"disease" column found in new data but not in existing data';
    }
    if (!hasdisease && dsc.hasdisease) {
      return '"disease" column found in existing data but not in new data';
    }
    if (hasst && !dsc.hasst) {
      return '"sampletype" column found in new data but not in existing data';
    }
    if (!hasst && dsc.hasst) {
      return '"sampletype" column found in existing data but not in new data';
    }
    for (const genename in flag2.data) {
      const lst = dsc.bulkdata[genename];
      if (lst) {
        dsc.bulkdata[genename] = lst.concat(flag2.data[genename]);
      } else {
        dsc.bulkdata[genename] = flag2.data[genename];
      }
    }
  } else {
    let dsname = p.filename + (flag2.tpsetname ? "_" + flag2.tpsetname : "");
    if (dsname in flag2.genome.datasets) {
      let j = 1;
      let n2 = dsname + " " + j;
      while (n2 in flag2.genome.datasets) {
        j++;
        n2 = dsname + " " + j;
      }
      dsname = n2;
    }
    dsc = {
      label: dsname,
      bulkdata: flag2.data,
      // official dataset don't have this
      hassample,
      hasdisease,
      hastumormaf,
      hasst,
      genome: cohort.genome,
      import: {},
      imported: {},
      importsilent: flag2.snv.silent == 0 ? false : flag2.snv.missense / flag2.snv.silent >= 5 ? false : true
    };
    flag2.genome.datasets[dsname] = dsc;
    cohort.dsset[dsname] = dsc;
    if (cohort.dbexpression) {
      if (cohort.dbexpression.tidy) {
        try {
          cohort.dbexpression.tidy = new Function(...cohort.dbexpression.tidy);
        } catch (e) {
          err("invalid JavaScript for dbexpression.tidy");
          delete cohort.dbexpression;
        }
      }
      dsc.dbexpression = cohort.dbexpression;
    }
    if (hasdisease) {
      dsc.stratify = [
        {
          label: "disease",
          attr1: { k: "disease", label: "disease" }
        }
      ];
    }
  }
  if (hassample) {
    for (const gene in flag2.data) {
      for (const m of flag2.data[gene]) {
        let pn = m.patient;
        if (!pn) {
          pn = m.sample;
          if (!pn) {
            continue;
          }
        }
        if (!cohort.p2st[pn]) {
          cohort.p2st[pn] = {};
        }
        let st = m.sampletype;
        if (!st) {
          st = pn;
        }
        if (!cohort.p2st[pn][st]) {
          cohort.p2st[pn][st] = {
            dsset: {},
            tktemplate: []
          };
        }
        if (!cohort.p2st[pn][st].dsset[dsc.label]) {
          cohort.p2st[pn][st].dsset[dsc.label] = [];
        }
        cohort.p2st[pn][st].dsset[dsc.label].push(m);
      }
    }
  }
  if (callback) callback();
  return false;
}
function bulkembed(arg) {
  if (!arg.name) arg.name = "Unnamed dataset";
  let holder = arg.holder;
  if (!holder) {
    const pane = newpane({ x: 100, y: 100 });
    holder = pane.body;
  }
  const saydiv = holder.append("div");
  new Promise((resolve, reject) => {
    const cohort = {
      dsset: {}
    };
    for (const k in arg) {
      if (k == "snvindel" || k == "svjson" || k == "cnv" || k == "sv" || k == "mutationset") {
        continue;
      }
      cohort[k] = arg[k];
    }
    resolve(cohort);
  }).then((cohort) => {
    if (!arg.snvindel && !arg.svjson && !arg.cnv && !arg.sv) return cohort;
    const flag2 = init_bulk_flag(cohort.genome);
    if (arg.snvindel) {
      const e = parse_snvindel(arg.snvindel, flag2);
      if (e) throw { message: "error in snvindel data: " + e };
      delete arg.snvindel;
    }
    if (arg.svjson) {
      const e = parse_svjson(arg.svjson, flag2);
      if (e) throw { message: "error in svjson data: " + e };
      delete arg.svjson;
    }
    if (arg.sv) {
      const e = parse_sv(arg.sv, flag2);
      if (e) throw { message: "error in svjson data: " + e };
      delete arg.sv;
    }
    if (arg.cnv) {
      const e = parse_cnv(arg.cnv, flag2);
      if (e) throw { message: "error in cnv data: " + e };
      delete arg.cnv;
    }
    const err2 = bulkin({
      flag: flag2,
      filename: arg.name,
      cohort
    });
    if (err2) throw { message: "Error parsing data: " + err2 };
    return cohort;
  }).then((cohort) => {
    if (!arg.mutationset) return cohort;
    if (!Array.isArray(arg.mutationset)) throw { message: "mutationset is not an array" };
    const tasks2 = [];
    for (const mset of arg.mutationset) {
      const flag2 = init_bulk_flag(cohort.genome);
      const tasks = [];
      if (mset.snvindel) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.snvindel + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with snvindel file: " + data.error };
          const e = parse_snvindel(data.text, flag2);
          if (e) throw { message: "error with snvindel file: " + e };
        });
        tasks.push(task);
      }
      if (mset.snvindel_url) {
        tasks.push(
          dofetch("urltextfile", { url: mset.snvindel_url }).then((data) => {
            if (data.error) throw { message: "cannot get snvindel file from url" };
            const e = parse_snvindel(data.text, flag2);
            if (e) throw { message: "error with snvindel file: " + e };
          })
        );
      }
      if (mset.cnv) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.cnv + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with cnv file: " + data.error };
          const e = parse_cnv(data.text, flag2);
          if (e) throw { message: "error with cnv file: " + e };
        });
        tasks.push(task);
      }
      if (mset.cnv_url) {
        tasks.push(
          dofetch("urltextfile", { url: mset.cnv_url }).then((data) => {
            if (data.error) throw { message: "cannot get cnv file from url" };
            const e = parse_cnv(data.text, flag2);
            if (e) throw { message: "error with cnv file: " + e };
          })
        );
      }
      if (mset.sv) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.sv + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with sv file: " + data.error };
          const e = parse_sv(data.text, flag2, true);
          if (e) throw { message: "error with sv file: " + e };
        });
        tasks.push(task);
      }
      if (mset.sv_url) {
        tasks.push(
          dofetch("urltextfile", { url: mset.sv_url }).then((data) => {
            if (data.error) throw { message: "cannot get sv file from url" };
            const e = parse_sv(data.text, flag2);
            if (e) throw { message: "error with sv file: " + e };
          })
        );
      }
      if (mset.fusion) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.fusion + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with fusion file: " + data.error };
          const e = parse_sv(data.text, flag2, false);
          if (e) throw { message: "error with fusion file: " + e };
        });
        tasks.push(task);
      }
      if (mset.svjson) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.svjson + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with svjson file: " + data.error };
          const e = parse_svjson(data.text, flag2, false);
          if (e) throw { message: "error with svjson file: " + e };
        });
        tasks.push(task);
      }
      if (mset.deletion) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.deletion + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with deletion file: " + data.error };
          const e = parse_del(data.text, flag2, false);
          if (e) throw { message: "error with deletion file: " + e };
        });
        tasks.push(task);
      }
      if (mset.deletion_url) {
        tasks.push(
          dofetch("urltextfile", { url: mset.deletion_url }).then((data) => {
            if (data.error) throw { message: "cannot get deletion file from url" };
            const e = parse_del(data.text, flag2);
            if (e) throw { message: "error with deletion file: " + e };
          })
        );
      }
      if (mset.truncation) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.truncation + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with truncation file: " + data.error };
          const e = parse_trunc(data.text, flag2, false);
          if (e) throw { message: "error with truncation file: " + e };
        });
        tasks.push(task);
      }
      if (mset.truncation_url) {
        tasks.push(
          dofetch("urltextfile", { url: mset.truncation_url }).then((data) => {
            if (data.error) throw { message: "cannot get truncation file from url" };
            const e = parse_trunc(data.text, flag2, false);
            if (e) throw { message: "error with truncation file: " + e };
          })
        );
      }
      if (mset.itd) {
        const req = new Request(arg.hostURL + "/textfile", {
          method: "POST",
          body: '{"file":"' + mset.itd + '"}'
        });
        const task = fetch(req).then((data) => {
          return data.json();
        }).then((data) => {
          if (data.error) throw { message: "error with itd file: " + data.error };
          const e = parse_itd(data.text, flag2, false);
          if (e) throw { message: "error with itd file: " + e };
        });
        tasks.push(task);
      }
      if (mset.itd_url) {
        tasks.push(
          dofetch("urltextfile", { url: mset.itd_url }).then((data) => {
            if (data.error) throw { message: "cannot get itd file from url" };
            const e = parse_itd(data.text, flag2, false);
            if (e) throw { message: "error with itd file: " + e };
          })
        );
      }
      const task2 = Promise.all(tasks).then((data) => {
        const err2 = bulkin({
          flag: flag2,
          filename: arg.name,
          cohort
        });
        if (err2) throw { message: "Error parsing data from " + mset.name + ": " + err2 };
      });
      tasks2.push(task2);
    }
    return Promise.all(tasks2).then((data) => {
      return cohort;
    });
  }).then((cohort) => {
    const err2 = tpinit(cohort);
    if (err2) throw { message: "Error parsing study: " + err2 };
    saydiv.text("");
    import("./tp.ui-T7FVMTGQ.js").then((p) => {
      p.default(cohort, holder, arg.hostURL);
    });
  }).catch((err2) => {
    saydiv.text(err2.message);
    if (err2.stack) {
      console.log(err2.stack);
    }
  });
}
function parse_snvindel(text, flag2) {
  const lines = text.trim().split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const err2 = parseheader2(headerline, flag2);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline2(i, lines[i], flag2);
  }
}
function parse_svjson(text, flag2) {
  const lines = text.split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const [err2, header] = parseheader3(headerline, flag2);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline3(i, lines[i], flag2, header);
  }
}
function parse_cnv(text, flag2) {
  const lines = text.split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const err2 = parseheader4(headerline, flag2);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline4(i, lines[i], flag2);
  }
}
function parse_itd(text, flag2) {
  const lines = text.split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const err2 = parseheader5(headerline, flag2);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline5(i, lines[i], flag2);
  }
}
function parse_del(text, flag2) {
  const lines = text.split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const err2 = parseheader6(headerline, flag2);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline6(i, lines[i], flag2);
  }
}
function parse_trunc(text, flag2) {
  const lines = text.split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const err2 = parseheader7(headerline, flag2);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline7(i, lines[i], flag2);
  }
}
function parse_sv(text, flag2, isSv) {
  const lines = text.split(/\r?\n/);
  let headerline = lines[0];
  let lineidx = 0;
  while (headerline[0] == "#") {
    lineidx++;
    headerline = lines[lineidx];
  }
  if (!headerline) return "no header line";
  const err2 = parseheader(headerline, flag2, isSv);
  if (err2) return "header error: " + err2;
  for (let i = lineidx + 1; i < lines.length; i++) {
    if (lines[i] == "") continue;
    if (lines[i][0] == "#") continue;
    parseline(i, lines[i], flag2, isSv);
  }
}

// src/tp.init.js
function tpinit(cohort) {
  if (!cohort.p2st) {
    cohort.p2st = {};
  }
  if (!cohort.assays) {
    cohort.assays = [];
  }
  if (!Array.isArray(cohort.assays)) {
    return ".assays should be an array";
  }
  cohort.assaylst = [];
  let assaynum = 0;
  for (const assayname of cohort.assays) {
    const rawassay = cohort[assayname];
    if (!rawassay) {
      return 'Assay "' + assayname + '" not found in cohort';
    }
    const config = rawassay.config;
    if (!config) {
      return '.config object missing for assay "' + assayname + '"';
    }
    delete rawassay.config;
    if (!config.type) {
      return '.config.type missing for assay "' + assayname + '"';
    }
    if (config.type.toLowerCase() == "vcf") {
      config.type = tkt.ds;
      config.isvcf = true;
    } else {
      if (!validtkt(config.type)) {
        return 'unknown .config.type "' + config.type + '" for assay "' + assayname + '"';
      }
    }
    config.id = (++assaynum).toString();
    if (!config.name) {
      config.name = assayname;
    }
    if (config.type == tkt.junction) {
      if (config.readcountcutoff) {
        if (!Number.isInteger(config.readcountcutoff) || config.readcountcutoff < 0) {
          return 'invalid .config.readcountcutoff for assay "' + assayname + '"';
        }
      }
    }
    cohort.assaylst.push(config);
    for (const pn in rawassay) {
      if (!cohort.p2st[pn]) {
        cohort.p2st[pn] = {};
      }
      for (const st in rawassay[pn]) {
        if (!cohort.p2st[pn][st]) {
          cohort.p2st[pn][st] = {
            tktemplate: []
          };
        }
        if (config.type == tkt.vafs1) {
          for (const name in rawassay[pn][st]) {
            const tk = rawassay[pn][st][name];
            if (!tk.file && !tk.url) {
              return "no file or URL for " + name + " vafs1 of " + pn + ", " + st;
            }
            tk.type = tkt.vafs1;
            tk.patient = pn;
            tk.sampletype = st;
            tk.assayname = assayname;
            tk.id = config.id;
            tk.tkid = Math.random().toString();
            if (!tk.name) {
              tk.name = name + " vaf";
            }
            cohort.p2st[pn][st].tktemplate.push(tk);
          }
          continue;
        }
        let rawtklst = [];
        if (Array.isArray(rawassay[pn][st])) {
          rawtklst = rawassay[pn][st];
        } else {
          rawtklst.push(rawassay[pn][st]);
        }
        for (const _tk of rawtklst) {
          let tk = _tk;
          if (!tk.file && !tk.url) {
            return "track has no file or url (sample: " + pn + ", assay: " + assayname + ")";
          }
          if (tk.name) {
          } else if (tk.partname) {
            tk.name = pn + (st == pn ? "" : " " + st) + " " + assayname + " " + tk.partname;
          } else {
            tk.name = pn + (st == pn ? "" : " " + st) + " " + assayname;
          }
          if (config.isvcf) {
            const [err2, tk2] = vcf2dstk({
              name: tk.name,
              file: tk.file,
              url: tk.url
            });
            if (err2) {
              return "VCF track error: " + err2;
            }
            tk = tk2;
          } else {
            if (tk.type) {
              if (!validtkt(tk.type)) {
                return 'invalid track type "' + tk.type + '" (sample: ' + pn + ", assay: " + assayname + ")";
              }
            } else {
              tk.type = config.type;
            }
          }
          tk.patient = pn;
          tk.sampletype = st;
          tk.assayname = assayname;
          tk.id = config.id;
          tk.tkid = Math.random().toString();
          cohort.p2st[pn][st].tktemplate.push(tk);
          switch (config.type) {
            case tkt.bigwig:
              const e = tidy_qtk(tk, config);
              if (e) {
                return "Assay " + assayname + ": " + config.type + " track error: " + e;
              }
              break;
            case tkt.junction:
              tk.categories = config.categories;
              tk.readcountcutoff = config.readcountcutoff;
              break;
          }
        }
      }
    }
  }
  delete cohort.assays;
  {
    const err2 = cohort2genometkset(cohort);
    if (err2) {
      return "Error: " + err2;
    }
  }
  if (cohort.patientannotation) {
    const err2 = parse_patientannotation(cohort);
    if (err2) return err2;
  }
  if (cohort.browserview) {
    const err2 = parse_browserview(cohort);
    if (err2) return err2;
  }
  if (cohort.e2pca) {
    if (!cohort.e2pca.list) return ".list missing from e2pca";
    if (!Array.isArray(cohort.e2pca.list)) return "e2pca.list should be an array";
    if (cohort.e2pca.list.length == 0) return "e2pca.list[] length 0";
    if (!cohort.e2pca.label) {
      cohort.e2pca.label = "Expression - PCA";
    }
    for (const obj of cohort.e2pca.list) {
      if (!obj.vectorfile) return "vectorfile missing from e2pca";
      if (!obj.dbfile) return "dbfile missing from e2pca";
    }
  }
  return;
}
function loadstudycohort(genomes, file, holder, hostURL, jwt, noshow, app) {
  const wait = holder.append("div").style("color", "#858585");
  wait.text("Loading " + file + " ...");
  return fetch(hostURL + "/study", {
    method: "POST",
    body: JSON.stringify({ file, jwt })
  }).then((res) => res.json()).then((data) => {
    if (!data) {
      wait.text("Server error!");
      return;
    }
    if (data.error) {
      wait.text("Error loading study: " + data.error);
      return;
    }
    const cohort = data.cohort;
    if (!cohort) {
      wait.text(".cohort missing");
      return;
    }
    if (!cohort.genome) {
      wait.text("No genome specified in the cohort JSON content");
      return;
    }
    const g = genomes[cohort.genome];
    if (!g) {
      wait.text("Invalid genome from cohort: " + cohort.genome);
      return;
    }
    cohort.genome = g;
    cohort.jwt = jwt;
    if (!data.flagset) {
      wait.text(".flagset missing");
      return;
    }
    wait.text("");
    cohort.dsset = {};
    for (const k in data.flagset) {
      const flag2 = data.flagset[k];
      flag2.genome = g;
      bulkin({
        flag: flag2,
        filename: file,
        cohort,
        err: (m) => sayerror(wait, m)
      });
    }
    const err2 = tpinit(cohort);
    if (err2) {
      sayerror(wait, err2);
    }
    if (!noshow) {
      return import("./tp.ui-T7FVMTGQ.js").then(async (p) => {
        getsjcharts().catch(console.error);
        p.default(cohort, holder, hostURL, app);
        return app;
      });
    }
  });
}
function tidy_qtk(tk, config) {
  if (!config) {
    config = {};
  }
  if (!tk.file && !tk.url) {
    return "no file or url";
  }
  if (!tk.pcolor) {
    tk.pcolor = config.pcolor || "#0066CC";
  }
  if (!tk.pcolor2) {
    tk.pcolor2 = config.pcolor2 || "#CC0000";
  }
  if (!tk.ncolor) {
    tk.ncolor = config.ncolor || "#FF850A";
  }
  if (!tk.ncolor2) {
    tk.ncolor2 = config.ncolor2 || "#0A85FF";
  }
  if (!tk.height) {
    tk.height = config.height || 50;
  }
  const scale = {};
  if (config.scale) {
    for (const k in config.scale) {
      scale[k] = config.scale[k];
    }
  }
  if (tk.scale) {
    for (const k in tk.scale) {
      scale[k] = tk.scale[k];
    }
  }
  scale.auto = true;
  if (Number.isFinite(scale.min) && Number.isFinite(scale.max)) {
    delete scale.auto;
  } else if (Number.isFinite(scale.percentile)) {
    delete scale.auto;
  }
  tk.scale = scale;
}
function cohort2genometkset(cohort) {
  const lst = [];
  for (const pn in cohort.p2st) {
    for (const st in cohort.p2st[pn]) {
      const templates = cohort.p2st[pn][st].tktemplate;
      if (!templates) continue;
      for (const t of templates) {
        lst.push(t);
      }
    }
  }
  if (cohort.browserview && cohort.browserview.assays) {
    for (const assayname in cohort.browserview.assays) {
      const assayview = cohort.browserview.assays[assayname];
      if (assayview.combined && assayview.combinetk) {
        lst.push(assayview.combinetk);
      }
    }
  }
  if (!cohort.genome.tkset) {
    cohort.genome.tkset = [];
  }
  const thisset = {
    name: cohort.name,
    tklst: lst
  };
  if (cohort.trackfacets) {
    if (!Array.isArray(cohort.trackfacets)) {
      return ".trackfacets is not an array";
    }
    const lst2 = [];
    for (const fc of cohort.trackfacets) {
      if (!fc.samples) {
        return "trackfacets: .samples missing from facet " + fc.name;
      }
      if (!Array.isArray(fc.samples)) {
        return "trackfacets: .samples is not array from facet " + fc.name;
      }
      if (!fc.assays) {
        return "trackfacets: .assays missing from a facet " + fc.name;
      }
      if (!Array.isArray(fc.assays)) {
        return "trackfacets: .assays is not array from a facet " + fc.name;
      }
      lst2.push(fc);
    }
    if (lst2.length) {
      thisset.facetlst = lst2;
    }
  }
  cohort.genome.tkset.push(thisset);
  return null;
}
function parse_browserview(cohort) {
  if (cohort.browserview.position) {
    let pos;
    if (typeof cohort.browserview.position == "string") {
      pos = string2pos(cohort.browserview.position, cohort.genome);
      if (!pos) {
        return ".browserview.position invalid value";
      }
    } else {
      pos = cohort.browserview.position;
    }
    const e = invalidcoord(cohort.genome, pos.chr, pos.start, pos.stop);
    if (e) {
      return ".browserview.position error: " + e;
    }
    cohort.browserview.position = pos;
  } else {
    cohort.browserview.position = {
      chr: cohort.genome.defaultcoord.chr,
      start: cohort.genome.defaultcoord.start,
      stop: cohort.genome.defaultcoord.stop
    };
  }
  if (cohort.browserview.assays) {
    for (const assayname in cohort.browserview.assays) {
      if (typeof cohort.browserview.assays[assayname] != "object") {
        cohort.browserview.assays[assayname] = {};
      }
      const assayview = cohort.browserview.assays[assayname];
      for (const a of cohort.assaylst) {
        if (a.name == assayname) {
          assayview.assayobj = a;
          break;
        }
      }
      if (!assayview.assayobj) {
        console.log("missing assayobj for assayview of " + assayname);
        continue;
      }
      if (assayview.sum_view) {
        delete assayview.sum_view;
        assayview.combined = true;
      }
      if (assayview.combined) {
        const combinetk = {};
        for (const k in assayview.assayobj) {
          combinetk[k] = assayview.assayobj[k];
        }
        for (const k in assayview) {
          if (k == "assayobj") continue;
          combinetk[k] = assayview[k];
        }
        if (!combinetk.name) {
          combinetk.name = assayname;
        }
        combinetk.tracks = [];
        for (const pn in cohort.p2st) {
          for (const st in cohort.p2st[pn]) {
            for (const t of cohort.p2st[pn][st].tktemplate) {
              if (t.id == assayview.assayobj.id) {
                t.patient = pn;
                t.sampletype = st;
                combinetk.tracks.push(t);
              }
            }
          }
        }
        if (combinetk.isvcf) {
          combinetk.ds = {
            id2vcf: {},
            label: combinetk.name
          };
          for (const t of combinetk.tracks) {
            for (const i in t.ds.id2vcf) {
              t.__vcfobj = t.ds.id2vcf[i];
            }
            combinetk.ds.id2vcf[t.__vcfobj.vcfid] = t.__vcfobj;
          }
        }
        assayview.combinetk = combinetk;
      }
    }
  }
  if (cohort.browserview.defaultassaytracks) {
    if (!Array.isArray(cohort.browserview.defaultassaytracks)) return ".browserview.defaultassaytracks must be array";
    for (let i = 0; i < cohort.browserview.defaultassaytracks.length; i++) {
      const t = cohort.browserview.defaultassaytracks[i];
      if (!t.assay) return ".assay missing from .defaultassaytracks #" + (i + 1);
      if (!cohort[t.assay]) return "unknown assay name from .defaultassaytracks #" + (i + 1) + ": " + t.assay;
      if (!t.level1) return ".level1 missing from .defaultassaytracks #" + (i + 1);
      if (!cohort[t.assay][t.level1])
        return "level1 not exist in assay from .defaultassaytracks #" + (i + 1) + ": " + t.level1;
      if (t.level2) {
        if (!cohort[t.assay][t.level1][t.level2])
          return "level2 not exist in assay from .defaultassaytracks #" + (i + 1) + ": " + t.level2;
      }
    }
  }
  return null;
}
function parse_patientannotation(cohort) {
  if (!cohort.patientannotation.annotation) {
    return ".patientannotation.annotation missing";
  }
  if (!cohort.patientannotation.metadata) {
    return ".patientannotation.metadata missing";
  }
  if (!Array.isArray(cohort.patientannotation.metadata)) {
    return ".patientannotation.metadata should be an array";
  }
  const mdh = {};
  for (const md of cohort.patientannotation.metadata) {
    if (md.key == void 0) {
      return "patientannotation: key missing for a metadata term";
    }
    if (!md.values) {
      return "patientannotation: values missing for metadata term " + md.key;
    }
    if (!Array.isArray(md.values)) {
      return "patientannotation: .values not an array for metadata term " + md.key;
    }
    if (!md.label) {
      md.label = md.key;
    }
    mdh[md.key] = {
      label: md.label,
      values: {}
    };
    const colorfunc = ordinal(category10_default);
    for (const at of md.values) {
      if (at.key == void 0) {
        return "key missing for an attribute of term " + md.key;
      }
      if (!at.label) {
        at.label = at.key;
      }
      if (!at.color) {
        at.color = colorfunc(at.key);
      }
      mdh[md.key].values[at.key] = at;
    }
  }
  cohort.patientannotation.mdh = mdh;
  return null;
}

export {
  loadstudycohort,
  bulkui,
  content2flag,
  bulkin,
  bulkembed
};
//# sourceMappingURL=chunk-ZTYNN6G5.js.map
