(()=>{
// === Visualization components ===

// ---------- Risk gauge ----------
const RiskGauge = ({ score, level="mid", size=180, label, sub }) => {
  const r = size/2 - 14;
  const cx = size/2, cy = size/2;
  const start = Math.PI * 0.8;
  const end = Math.PI * 2.2;
  const arc = (t) => {
    const a = start + (end - start) * t;
    return [cx + r*Math.cos(a), cy + r*Math.sin(a)];
  };
  const trackD = describeArc(cx, cy, r, start, end);
  const valD   = describeArc(cx, cy, r, start, start + (end-start) * (score/100));
  const color  = level==="high" ? "#C9342B" : level==="mid" ? "#C2761A" : "#0E8367";
  return (
    <div className="relative inline-flex flex-col items-center" style={{width:size}}>
      <svg width={size} height={size*0.72} viewBox={`0 0 ${size} ${size*0.86}`}>
        <path d={trackD} stroke="#E8EEF6" strokeWidth="10" fill="none" strokeLinecap="round"/>
        <path d={valD}   stroke={color}  strokeWidth="10" fill="none" strokeLinecap="round"/>
        {/* tick marks */}
        {[0,0.25,0.5,0.75,1].map((t,i)=>{
          const [x1,y1]=arc(t); const [x2,y2]=[cx + (r-8)*Math.cos(start+(end-start)*t), cy + (r-8)*Math.sin(start+(end-start)*t)];
          return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#B3C2D6" strokeWidth="1.2"/>;
        })}
        <text x={cx} y={cy-2} textAnchor="middle" className="num" fontSize={size*0.26} fontWeight="600" fill="#0B1B2B">{score}</text>
        <text x={cx} y={cy+size*0.12} textAnchor="middle" fontSize={size*0.07} fill="#5C7390">/ 100</text>
      </svg>
      {label && <div className="text-sm font-medium text-ink-800 mt-1">{label}</div>}
      {sub && <div className="text-xs text-ink-500">{sub}</div>}
    </div>
  );
};

function describeArc(cx, cy, r, start, end){
  const x1=cx+r*Math.cos(start), y1=cy+r*Math.sin(start);
  const x2=cx+r*Math.cos(end),   y2=cy+r*Math.sin(end);
  const large = (end-start) > Math.PI ? 1 : 0;
  return `M ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2}`;
}

// ---------- Compact horizontal risk bar ----------
const RiskBar = ({ score, level }) => {
  const color = level==="high" ? "#C9342B" : level==="mid" ? "#C2761A" : "#0E8367";
  return (
    <div className="w-full">
      <div className="h-2 rounded-full bg-ink-100 relative overflow-hidden">
        <div className="absolute inset-y-0 left-0 rounded-full" style={{width:`${score}%`, background:color}}/>
        {/* threshold ticks */}
        <div className="absolute top-0 bottom-0" style={{left:"30%", width:1, background:"#B3C2D6"}}/>
        <div className="absolute top-0 bottom-0" style={{left:"60%", width:1, background:"#B3C2D6"}}/>
      </div>
      <div className="flex justify-between text-[10px] num text-ink-400 mt-1">
        <span>0</span><span>30 低</span><span>60 中</span><span>100 高</span>
      </div>
    </div>
  );
};

// ---------- Oral cavity SVG illustration ----------
const OralImage = ({ width=520, height=360, showROI=false, showMask=false, raw=false }) => {
  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="xMidYMid meet" className="block">
      <defs>
        <radialGradient id="cavity" cx="50%" cy="55%" r="55%">
          <stop offset="0%" stopColor="#3A1418"/>
          <stop offset="60%" stopColor="#1A080A"/>
          <stop offset="100%" stopColor="#0A0405"/>
        </radialGradient>
        <radialGradient id="lipsTop" cx="50%" cy="100%" r="80%">
          <stop offset="0%" stopColor="#B14552"/>
          <stop offset="100%" stopColor="#7C2C36"/>
        </radialGradient>
        <radialGradient id="lipsBot" cx="50%" cy="0%" r="80%">
          <stop offset="0%" stopColor="#A23B47"/>
          <stop offset="100%" stopColor="#6A2530"/>
        </radialGradient>
        <radialGradient id="tongue" cx="50%" cy="40%" r="60%">
          <stop offset="0%" stopColor="#D77B82"/>
          <stop offset="60%" stopColor="#B14F58"/>
          <stop offset="100%" stopColor="#7C2933"/>
        </radialGradient>
        <linearGradient id="gum" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#E07682"/>
          <stop offset="100%" stopColor="#B4424E"/>
        </linearGradient>
        <linearGradient id="gumLow" x1="0" y1="1" x2="0" y2="0">
          <stop offset="0%" stopColor="#D86B77"/>
          <stop offset="100%" stopColor="#A53846"/>
        </linearGradient>
        <pattern id="toothShine" patternUnits="objectBoundingBox" width="1" height="1">
          <rect width="1" height="1" fill="#FBF8F0"/>
          <rect width="1" height="0.15" fill="#FFFFFF" opacity="0.55"/>
        </pattern>
      </defs>

      {/* outer face skin (subtle) */}
      <rect x="0" y="0" width={width} height={height} fill="#F2D6C5"/>
      {/* mouth opening cavity */}
      <ellipse cx={width/2} cy={height*0.55} rx={width*0.46} ry={height*0.42} fill="url(#cavity)"/>

      {/* upper lip */}
      <path d={`M ${width*0.05} ${height*0.43} Q ${width*0.25} ${height*0.18}, ${width*0.5} ${height*0.32} T ${width*0.95} ${height*0.43} Q ${width*0.7} ${height*0.5}, ${width*0.5} ${height*0.45} T ${width*0.05} ${height*0.43} Z`} fill="url(#lipsTop)"/>
      {/* lower lip */}
      <path d={`M ${width*0.05} ${height*0.7} Q ${width*0.25} ${height*0.97}, ${width*0.5} ${height*0.82} T ${width*0.95} ${height*0.7} Q ${width*0.7} ${height*0.62}, ${width*0.5} ${height*0.7} T ${width*0.05} ${height*0.7} Z`} fill="url(#lipsBot)"/>

      {/* upper gum */}
      <path d={`M ${width*0.13} ${height*0.46} Q ${width*0.5} ${height*0.38}, ${width*0.87} ${height*0.46} L ${width*0.85} ${height*0.55} Q ${width*0.5} ${height*0.5}, ${width*0.15} ${height*0.55} Z`} fill="url(#gum)"/>
      {/* lower gum */}
      <path d={`M ${width*0.16} ${height*0.7} Q ${width*0.5} ${height*0.78}, ${width*0.84} ${height*0.7} L ${width*0.82} ${height*0.62} Q ${width*0.5} ${height*0.66}, ${width*0.18} ${height*0.62} Z`} fill="url(#gumLow)"/>

      {/* tongue */}
      <ellipse cx={width/2} cy={height*0.66} rx={width*0.22} ry={height*0.13} fill="url(#tongue)"/>
      {/* tongue coating texture */}
      <ellipse cx={width/2} cy={height*0.64} rx={width*0.18} ry={height*0.09} fill="#E2B9B0" opacity="0.35"/>
      {/* tongue mid-line */}
      <path d={`M ${width/2} ${height*0.55} Q ${width*0.5} ${height*0.66}, ${width/2} ${height*0.77}`} stroke="#6A2530" strokeWidth="1" opacity="0.45" fill="none"/>

      {/* upper teeth */}
      {Array.from({length:8}).map((_,i)=>{
        const tw = width*0.07, x = width*0.18 + i*tw, y = height*0.5;
        return <rect key={`ut${i}`} x={x} y={y} width={tw*0.85} height={height*0.06} rx="2" fill="url(#toothShine)" stroke="#E2D5BD" strokeWidth="0.5"/>;
      })}
      {/* lower teeth */}
      {Array.from({length:8}).map((_,i)=>{
        const tw = width*0.07, x = width*0.18 + i*tw, y = height*0.65;
        return <rect key={`lt${i}`} x={x} y={y} width={tw*0.85} height={height*0.055} rx="2" fill="url(#toothShine)" stroke="#E2D5BD" strokeWidth="0.5"/>;
      })}

      {/* gum redness highlight (inflammation marker) — only if not raw */}
      {!raw && (
        <g opacity="0.55">
          <ellipse cx={width*0.32} cy={height*0.485} rx="14" ry="5" fill="#D8312F"/>
          <ellipse cx={width*0.5}  cy={height*0.476} rx="18" ry="6" fill="#D8312F"/>
          <ellipse cx={width*0.66} cy={height*0.49}  rx="14" ry="5" fill="#D8312F"/>
        </g>
      )}

      {/* ROI overlays */}
      {showROI && (
        <g fontFamily='"IBM Plex Sans", "Noto Sans SC"' fontSize="11">
          {/* Gingiva */}
          <rect x={width*0.16} y={height*0.46} width={width*0.7} height={height*0.10} fill="none" stroke="#E66B7A" strokeDasharray="4 4" strokeWidth="1.5"/>
          <rect x={width*0.16} y={height*0.46} width={50} height={16} fill="#E66B7A"/>
          <text x={width*0.16+25} y={height*0.46+11.5} textAnchor="middle" fill="#fff" fontWeight="600">牙龈 GUM</text>

          {/* Tongue */}
          <ellipse cx={width/2} cy={height*0.66} rx={width*0.23} ry={height*0.14} fill="none" stroke="#C24B5B" strokeDasharray="4 4" strokeWidth="1.5"/>
          <rect x={width*0.5-32} y={height*0.66+height*0.15} width={64} height={16} fill="#C24B5B"/>
          <text x={width*0.5} y={height*0.66+height*0.15+11.5} textAnchor="middle" fill="#fff" fontWeight="600">舌面 TONGUE</text>

          {/* Mucosa (left cheek) */}
          <rect x={width*0.03} y={height*0.5} width={width*0.12} height={height*0.22} fill="none" stroke="#D88EA0" strokeDasharray="4 4" strokeWidth="1.5"/>
          <rect x={width*0.03} y={height*0.5-16} width={70} height={16} fill="#D88EA0"/>
          <text x={width*0.03+35} y={height*0.5-4} textAnchor="middle" fill="#fff" fontWeight="600">黏膜 MUCOSA</text>
        </g>
      )}

      {/* Segmentation mask overlay */}
      {showMask && (
        <g>
          <rect x={width*0.16} y={height*0.46} width={width*0.7} height={height*0.10} fill="#E66B7A" opacity="0.42"/>
          <ellipse cx={width/2} cy={height*0.66} rx={width*0.21} ry={height*0.12} fill="#C24B5B" opacity="0.42"/>
          <rect x={width*0.03} y={height*0.5} width={width*0.12} height={height*0.22} fill="#D88EA0" opacity="0.42"/>
        </g>
      )}
    </svg>
  );
};

// ---------- Color checker card on photo ----------
const ColorChecker = ({ size=64 }) => {
  const patches = window.DATA.COLOR_PATCHES;
  return (
    <div className="grid grid-cols-6 gap-[2px] p-1 bg-white/90 rounded shadow-sm" style={{width:size*1.4}}>
      {patches.flat().map((c,i)=>(
        <div key={i} style={{background:c, aspectRatio:"1/1", borderRadius:1}}/>
      ))}
    </div>
  );
};

// ---------- LAB 3D-ish scatter (before/after) ----------
const LabScatter = ({ width=320, height=220, before, after }) => {
  // axes: a* (x), b* (y), L* (size). before/after each is {a, b, L}
  const ax2x = a => width/2 + (a/30)*(width*0.42);
  const b2y = b => height/2 - (b/30)*(height*0.42);
  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`}>
      {/* grid */}
      <rect x="0" y="0" width={width} height={height} fill="#F4F7FB"/>
      {[-20,-10,0,10,20].map(v=>(
        <g key={v}>
          <line x1={ax2x(v)} y1="20" x2={ax2x(v)} y2={height-20} stroke="#E5EBF3"/>
          <line x1="20" y1={b2y(v)} x2={width-20} y2={b2y(v)} stroke="#E5EBF3"/>
        </g>
      ))}
      <line x1={ax2x(0)} y1="20" x2={ax2x(0)} y2={height-20} stroke="#B3C2D6"/>
      <line x1="20" y1={b2y(0)} x2={width-20} y2={b2y(0)} stroke="#B3C2D6"/>
      {/* axes labels */}
      <text x={width-22} y={b2y(0)-4} textAnchor="end" fontSize="10" fill="#5C7390">+ a* 红</text>
      <text x="24" y={b2y(0)-4} fontSize="10" fill="#5C7390">绿 −a*</text>
      <text x={ax2x(0)+6} y="28" fontSize="10" fill="#5C7390">+ b* 黄</text>
      <text x={ax2x(0)+6} y={height-22} fontSize="10" fill="#5C7390">− b* 蓝</text>

      {/* before cluster */}
      {before.map((p,i)=>(
        <circle key={i} cx={ax2x(p.a)} cy={b2y(p.b)} r={p.r||5} fill="#B3C2D6" stroke="#5C7390" strokeWidth="1"/>
      ))}
      {/* after cluster */}
      {after.map((p,i)=>(
        <circle key={i} cx={ax2x(p.a)} cy={b2y(p.b)} r={p.r||5} fill="#1E7AC8" stroke="#0B4A82" strokeWidth="1"/>
      ))}
      {/* arrow from cluster center */}
      {(()=>{
        const bx = before.reduce((s,p)=>s+p.a,0)/before.length;
        const by = before.reduce((s,p)=>s+p.b,0)/before.length;
        const ax = after.reduce((s,p)=>s+p.a,0)/after.length;
        const ay = after.reduce((s,p)=>s+p.b,0)/after.length;
        return <g>
          <line x1={ax2x(bx)} y1={b2y(by)} x2={ax2x(ax)} y2={b2y(ay)} stroke="#C2761A" strokeWidth="1.5" strokeDasharray="3 3"/>
          <polygon points={`${ax2x(ax)},${b2y(ay)} ${ax2x(ax)-6},${b2y(ay)-3} ${ax2x(ax)-6},${b2y(ay)+3}`} fill="#C2761A"/>
        </g>;
      })()}
    </svg>
  );
};

// ---------- 20-dim feature radar ----------
const FeatureRadar = ({ features, size=320 }) => {
  const n = features.length;
  const cx = size/2, cy = size/2;
  const rMax = size*0.4;
  const points = features.map((f,i)=>{
    const a = (i/n) * Math.PI*2 - Math.PI/2;
    // normalize z-score: 0=norm, ±3=edge
    const v = Math.min(1, Math.max(0, 0.4 + (f.z/3)*0.5));
    return [cx + Math.cos(a)*rMax*v, cy + Math.sin(a)*rMax*v];
  });
  const refPoints = features.map((_,i)=>{
    const a = (i/n) * Math.PI*2 - Math.PI/2;
    return [cx + Math.cos(a)*rMax*0.4, cy + Math.sin(a)*rMax*0.4];
  });
  const polyD  = "M " + points.map(p=>p.join(" ")).join(" L ") + " Z";
  const refD   = "M " + refPoints.map(p=>p.join(" ")).join(" L ") + " Z";
  return (
    <svg width="100%" viewBox={`0 0 ${size} ${size}`}>
      {/* concentric grid */}
      {[0.25,0.5,0.75,1].map(t=>(
        <circle key={t} cx={cx} cy={cy} r={rMax*t} fill="none" stroke="#E5EBF3"/>
      ))}
      {/* radial lines */}
      {features.map((f,i)=>{
        const a = (i/n)*Math.PI*2 - Math.PI/2;
        return <line key={i} x1={cx} y1={cy} x2={cx+Math.cos(a)*rMax} y2={cy+Math.sin(a)*rMax} stroke="#E5EBF3"/>;
      })}
      {/* reference (normal z=0) */}
      <path d={refD} fill="#BEDCF2" fillOpacity="0.25" stroke="#7DB8E8" strokeWidth="1" strokeDasharray="3 3"/>
      {/* actual */}
      <path d={polyD} fill="#1E7AC8" fillOpacity="0.18" stroke="#1462AB" strokeWidth="1.5"/>
      {/* dots colored by signal */}
      {points.map((p,i)=>{
        const sig = features[i].signal;
        const c = sig==="high" ? "#C9342B" : sig==="mid" ? "#C2761A" : sig==="low" ? "#7DB8E8" : "#1462AB";
        return <circle key={i} cx={p[0]} cy={p[1]} r="3" fill={c}/>;
      })}
      {/* labels */}
      {features.map((f,i)=>{
        const a = (i/n)*Math.PI*2 - Math.PI/2;
        const lx = cx + Math.cos(a)*(rMax+12);
        const ly = cy + Math.sin(a)*(rMax+12);
        const anchor = Math.cos(a) > 0.2 ? "start" : Math.cos(a) < -0.2 ? "end" : "middle";
        return <text key={i} x={lx} y={ly} textAnchor={anchor} dominantBaseline="middle" fontSize="9" fill="#22364F">{f.name.split(" ")[0]}</text>;
      })}
    </svg>
  );
};

// ---------- SHAP waterfall ----------
const ShapWaterfall = ({ items, base=0, width=540, height=320 }) => {
  // sort by abs descending
  const sorted = [...items].sort((a,b)=>Math.abs(b.value)-Math.abs(a.value));
  const total = sorted.reduce((s,i)=>s+i.value, base);
  const rowH = 26;
  const maxAbs = Math.max(...items.map(i=>Math.abs(i.value)), Math.abs(total-base)) * 1.2;
  const scale = (width*0.42) / maxAbs;
  const baseX = width*0.46;

  let running = base;
  const rows = sorted.map((it,i)=>{
    const x1 = baseX + running*scale;
    running += it.value;
    const x2 = baseX + running*scale;
    return { ...it, x1, x2, y: 30 + i*rowH };
  });
  const finalY = 30 + sorted.length*rowH + 8;

  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`} fontFamily='"IBM Plex Sans","Noto Sans SC"'>
      {/* baseline */}
      <line x1={baseX} y1="20" x2={baseX} y2={finalY+10} stroke="#B3C2D6" strokeDasharray="3 3"/>
      <text x={baseX} y="14" textAnchor="middle" fontSize="10" fill="#5C7390">基线 E[f(x)] = {base.toFixed(2)}</text>

      {rows.map((r,i)=>{
        const up = r.value > 0;
        const x = Math.min(r.x1, r.x2);
        const w = Math.abs(r.x2 - r.x1);
        return (
          <g key={i}>
            <text x={baseX-8} y={r.y+rowH*0.55} textAnchor="end" fontSize="11" fill="#22364F">{r.feature}</text>
            <rect x={x} y={r.y+4} width={w} height={rowH-10} fill={up?"#E66B7A":"#7DB8E8"} stroke={up?"#C9342B":"#1462AB"}/>
            {/* arrow tip */}
            <polygon points={up
              ? `${r.x2},${r.y+rowH/2} ${r.x2-6},${r.y+4} ${r.x2-6},${r.y+rowH-6}`
              : `${r.x2},${r.y+rowH/2} ${r.x2+6},${r.y+4} ${r.x2+6},${r.y+rowH-6}`}
              fill={up?"#C9342B":"#1462AB"}/>
            <text x={r.x2 + (up?10:-10)} y={r.y+rowH*0.6} textAnchor={up?"start":"end"} fontSize="10" className="num" fill={up?"#C9342B":"#1462AB"}>
              {(r.value>0?"+":"")+r.value.toFixed(3)}
            </text>
          </g>
        );
      })}

      {/* total marker */}
      <line x1={baseX+total*scale} y1={finalY-6} x2={baseX+total*scale} y2={finalY+18} stroke="#0B1B2B" strokeWidth="1.5"/>
      <text x={baseX+total*scale} y={finalY+30} textAnchor="middle" fontSize="11" fontWeight="600" fill="#0B1B2B" className="num">
        f(x) = {total.toFixed(2)}  →  σ(f) = {(1/(1+Math.exp(-total))*100).toFixed(0)}%
      </text>
    </svg>
  );
};

// ---------- History line chart ----------
const HistoryChart = ({ data, width=580, height=240 }) => {
  const pad = { l:36, r:20, t:20, b:30 };
  const w = width-pad.l-pad.r, h = height-pad.t-pad.b;
  const n = data.length;
  const x = i => pad.l + (i/(n-1))*w;
  const y = v => pad.t + h - (v/100)*h;
  const lines = [
    { key:"dm", color:"#C9342B", label:"糖尿病" },
    { key:"cv", color:"#C2761A", label:"心血管" },
    { key:"kd", color:"#1462AB", label:"肾病" },
    { key:"an", color:"#0E8367", label:"贫血" },
  ];
  return (
    <svg width="100%" viewBox={`0 0 ${width} ${height}`}>
      {/* gridlines */}
      {[0,25,50,75,100].map(v=>(
        <g key={v}>
          <line x1={pad.l} y1={y(v)} x2={width-pad.r} y2={y(v)} stroke="#E5EBF3"/>
          <text x={pad.l-6} y={y(v)+3} textAnchor="end" fontSize="10" fill="#5C7390" className="num">{v}</text>
        </g>
      ))}
      {/* x labels */}
      {data.map((d,i)=>(
        <text key={i} x={x(i)} y={height-pad.b+14} textAnchor="middle" fontSize="9" fill="#5C7390" className="num">{d.date.slice(5)}</text>
      ))}
      {/* threshold bands */}
      <rect x={pad.l} y={y(60)} width={w} height={y(30)-y(60)} fill="#FBEFD9" opacity="0.4"/>
      <rect x={pad.l} y={y(100)} width={w} height={y(60)-y(100)} fill="#FDECEA" opacity="0.4"/>

      {lines.map(L=>{
        const d = "M " + data.map((p,i)=>`${x(i)} ${y(p[L.key])}`).join(" L ");
        return (
          <g key={L.key}>
            <path d={d} stroke={L.color} strokeWidth="1.8" fill="none"/>
            {data.map((p,i)=>(
              <circle key={i} cx={x(i)} cy={y(p[L.key])} r="3" fill="#fff" stroke={L.color} strokeWidth="1.5"/>
            ))}
          </g>
        );
      })}
      {/* legend */}
      <g transform={`translate(${pad.l+8},${pad.t+4})`}>
        {lines.map((L,i)=>(
          <g key={L.key} transform={`translate(${i*78},0)`}>
            <rect width="10" height="3" y="6" fill={L.color}/>
            <text x="14" y="10" fontSize="10" fill="#22364F">{L.label}</text>
          </g>
        ))}
      </g>
    </svg>
  );
};

// ---------- Architecture pipeline diagram ----------
const ArchPipeline = () => {
  const stages = [
    { n: "01", title:"采集 & 色彩标准化", sub:"色卡检测 → LAB 仿射 → D65", icon:"camera", color:"#1E7AC8" },
    { n: "02", title:"SAM2 区域分割",      sub:"牙龈 / 舌面 / 黏膜 ROI",      icon:"target", color:"#13A37D" },
    { n: "03", title:"特征工程 (20维)",    sub:"LAB+HSV+纹理 可解释特征",     icon:"filter", color:"#C2761A" },
    { n: "04", title:"XGBoost 多标签",     sub:"4 个独立树模型 + SHAP",        icon:"cpu",    color:"#7C3AED" },
  ];
  return (
    <div className="flex items-stretch gap-2">
      {stages.map((s,i)=>(
        <React.Fragment key={i}>
          <div className="tech-frame flex-1 p-4">
            <div className="flex items-center justify-between mb-2">
              <span className="num text-xs text-ink-400">{s.n}</span>
              <div className="w-8 h-8 rounded-md flex items-center justify-center" style={{background:s.color+"15", color:s.color}}>
                <Icon name={s.icon} size={16}/>
              </div>
            </div>
            <div className="text-sm font-semibold text-ink-900">{s.title}</div>
            <div className="text-xs text-ink-500 mt-1">{s.sub}</div>
          </div>
          {i < stages.length-1 && (
            <div className="flex items-center text-ink-300">
              <svg width="24" height="40" viewBox="0 0 24 40"><path className="flow-line" d="M2 20 H 22" stroke="#1E7AC8" strokeWidth="1.5" fill="none"/><polygon points="20,16 24,20 20,24" fill="#1E7AC8"/></svg>
            </div>
          )}
        </React.Fragment>
      ))}
    </div>
  );
};

window.Viz = { RiskGauge, RiskBar, OralImage, ColorChecker, LabScatter, FeatureRadar, ShapWaterfall, HistoryChart, ArchPipeline };

})();
