const typeOf=arg=>Object.prototype.toString.call(arg).slice(8,-1);
const fileLoader=async(path,enc)=>new TextDecoder(enc).decode(await(await fetch(path)).arrayBuffer());
const Ajax=async(path,prm={})=>(await(await fetch(path,{method:'post',body:JSON.stringify(prm)}))).json();
const getURLQuery=(url=window.location)=>Object.fromEntries(new URLSearchParams(url.search));
const appendOption=(elm,ary)=>elm.append(...ary.map(args=>new Option(...args)));
const replaceSelect=(elm,ary)=>elm.replaceChildren(...ary.map(args=>new Option(...args)));
const ary2tbody=(a,b=document.createElement('tbody'))=>a.reduce((b,a)=>(a.reduce((c,d)=>(c.insertCell().append(d),c),b.insertRow()),b),b);
ary2thead=(a=[],b=document.createElement('thead'))=>{
let A='^(#)?(?:!(?=[rc\\{])(?:r([2-9]|[1-9]\\d+)|r[01]|r0\\d+)?(?:c([2-9]|[1-9]\\d+)|c[01]|c0\\d+)?(?:\\{(.+)?\\})?)?\\s*(.*)\\s*$',B=RegExp,C=Object;
a.map(c=>{b.insertRow().append(...c.map(d=>{let[,z,y,x,w,v]=(new B(A,'i')).exec(d)??[],u={rowSpan:y,colSpan:x,textContent:v};
C.entries(u).map(a=>a[1]===undefined&&delete u[a[0]]);for(let a,b=new B('\\s*(.+?)\\s*\\:\\s*(.*?)\\s*(,|;|$)','g');a=b.exec(w);u[a[1]]=a[2]);
return C.assign(document.createElement(z?'th':'td'),u)}))});return b};
const csv2ary = csv => csv.split (/r\n|\r|\n/g).reduce ((a,b)=>b.trim()?[...a,b]:a,[]).map (row=> row.split (/\t/g));
const transpose=a=>a[0].map((_,i)=>a.map(b=>b[i]));
const rotateRight = a=> a[0].map((_,i)=>a.reduceRight((b,c)=>[...b,c[i]],[]));
const inversion = a=>a.reduceRight((b,c)=>[...b,c.reduceRight((d,e)=>[...d,e],[])],[]);
const rotateLeft = a=> a[0].reduceRight((b,_,i)=>[...b,a.map(c=>c[i])],[]);
const permutations=((F=(a=[],b=a.length,c=1)=>2>b?a.map(d=>[d]):a.flatMap((d,e,[...f])=> F((f.splice(e,1-c),f),b-1,c).map(a=>[d,...a])))=>F)();
const combinations=((f=(a=[],b=a.length,c=1)=>2>b?a.map(d=>[d]):a.flatMap((d,e)=>f(a.slice (e+1-c),b-1,c).map(a=>[d,...a])))=>f)();
class P2{
constructor(x=0,y=0){this.x=x;this.y=y}
get clone(){return new this.constructor(this.x, this.y)}
get toArray(){return[this.x,this.y]}
add({x=0,y=0},{x:X,y:Y}=this){this.x=X+x;this.y=Y+y;return this}
sub({x=0,y=0},{x:X,y:Y}=this){this.x=X-X;this.y=Y-y;return this}
mul({x=0,y=0},{x:X,y:Y}=this){this.x=X*x;this.y=Y*y;return this}
div({x=0,y=0},{x:X,y:Y}=this){this.x=X/x;this.y=Y/y;return this}
sMul(n=0,{x:X,y:Y}=this){this.x=X*n;this.y=Y*n;return this}
}
class V2 extends P2{
constructor(...p){super(...p)}
get length(){return(this.x**2+this.y**2)**.5}
get negate(){this.x=-this.x;this.y=-this.y;return this}
get normalize(){let L=1/(this.length||1);this.x*=L;this.y*=L;return this}
get angle(){return Math.atan2(-this.y,-this.x)+Math.PI}
dot({x=0,y=0},{x:X,y:Y}=this){return X*x+Y*y}
cross({x=0,y=0},{x:X,y:Y}=this){return X*y-Y*x}
rotation(a){let m=Math,s=m.sin(a),c=m.cos(a),{x,y}=this;this.x=x*c+y*s;this.y=x*-s+y*c;return this}
}
class P3{
constructor(x=0,y=0,z=0){this.x=x,this.y=y,this.z=z}
get clone(){return new this.constructor(this.x,this.y,this.z)}
get toArray(){return[this.x,this.y,this.z]}
add({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X+x;this.y=Y+y;this.z=Z+z;return this}
sub({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X-x;this.y=Y-y;this.z=Z-z;return this}
mul({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X*x;this.y=Y*y;this.z=Z*z;return this}
div({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X/x;this.y=Y/y;this.z=Z/z;return this}
sMul(n=0,{x:X,y:Y,z:Z}=this){this.x=X*n;this.y=Y*n;this.z=Z*n;return this}
applyQuaternion({x=0,y=0,z=0,w=1},{x:X,y:Y,z:Z}=this){
let a=w*X+y*Z-z*Y,b=w*Y+z*X-x*Z,c=w*Z+x*Y-y*X,d=-x*X-y*Y-z*Z;
return this.x=a*w+d*-x+b*-z-c*-y,this.y=b*w+d*-y+c*-x-a*-z,this.z=c*w+d*-z+a*-y-b*-x,this;
}
rotation(a=0,b=0,c=0){
let {sin:S,cos:C,PI}=Math,{x,y,z}=this,d=PI/180,e=a*d,f=b*d,g=c*d,h=S(e),i=S(f),j=S(g),k=C(e),l=C(f),m=C(g);
this.x=x*k*l+y*(k*i*j-h*m)+z*(k*i*m+h*j);this.y=x*h*l+y*(h*i*j+k*m)+z*(h*i*m-k*j);this.z=x*-i+y*l*j+z*l*m;return this;
}
}
class Vector extends P3{
constructor(...p){super(...p)}
get length(){return(this.x**2+this.y**2+this.z**2)**.5}
get clone(){return new this.constructor(this.x,this.y,this.z)}
get negate(){return this.sMul(-1)}
get normalize(){return this.sMul(1/(this.length||1))}
dot({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){return X*x+Y*y+Z*z}
cross ({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){return this.x=y*Z-z*Y,this.y=z*X-x*Z,this.z=x*Y-y*X,this}
rotation (a=0,b=0) {
let {sin:S,cos:C,PI}=Math,{x,y,z}=this,d=PI/360,e=a*d,f=b*d,g=S(e),h=S(f),
A=(new Vector(-z,0,(!z&&!x?1:x)).normalize),B=(new Vector(x,y,z).normalize);
return this.applyQuaternion(new Quaternion(A.x*g,A.y*g,A.z*g,C(e))).applyQuaternion(new Quaternion(B.x*h,B.y*h,B.z*h,C(f)));
}
}
class Quaternion{
constructor (x=0,y=0,z=0,w=1){this.x=x;this.y=y;this.z=z;this.w=w}
get clone(){return new this.constructor(this.x,this.y,this.z,this.w)}
get length(){return(this.x**2+this.y**2+this.z**2+this.w**2)**.5}
get normalize(){let L=this.length;return (L?(L=1/L,this.x*=L,this.y*=L,this.z*=L,this.w*=L):this.x=this.y=this.z=0,this.w=1),this}
dot({x=0,y=0,z=0,w=1},{x:X,y:Y,z:Z,w:W}=this){return X*x+Y*y+Z*z+W*w}
mul({x=0,y=0,z=0,w=1},{x:X,y:Y,z:Z,w:W}=this){return this.x=X*w+W*x+Y*z-Z*y,this.y=Y*w+W*y+Z*x-X*z,this.z=Z*w+W*z+X*y-Y*x,this.w=W*w-X*x-Y*y-Z*z,this}
add({x,y,z,w}){return this.x+=x,this.y+=y,this.z+=z,this.w+=w,this}
setFromAxisAngle(a=0,_){this.w*=Math.cos(_=a/2);this.x*=(_=Math.sin(_));this.y*=_;this.z*=_;return this}
}
function deriveFromTemplate (template, recs = [ ]) {
let tp = ('TEMPLATE' === template.tagName)
? template.content.cloneNode (true)
: template.cloneNode (true);
let es = [...tp.querySelectorAll ('*[name]')];
let rst = [ ];
for (let rec of recs) {
for (let e of es) {
let name = e.name;
if (rec.hasOwnProperty (name)) {
let val = rec[name];
e.value = (val != null) ? val: '';
}
}
rst.push (tp.cloneNode (true));
}
return rst;
}
function replaceBeforeFromTemplate (template, elements = [ ]) {
if ('TEMPLATE' !== template.tagName)
throw new Error ();
for (let e; e = template.previousElementSibling; ) {
if ('TEMPLATE' === e.tagName)
break;
e.remove ();
}
if (elements.length)
template.before (...elements);
}
function replaceAfterFromTemplate (template, elements = [ ]) {
if ('TEMPLATE' !== template.tagName)
throw new Error ();
for (let e; e = template.nextElementSibling; ) {
if ('TEMPLATE' === e.tagName)
break;
e.remove ();
}
if (elements.length)
template.after (...elements);
}
function kansuji(a,t=0,r='',N=[...'〇一二三四五六七八九'],M=['',...'十百千'],K=['',...'万億兆京垓𥝱穣溝澗']){
return(''+a).replace(/(\d+)/g,a=>{
if(t||'0'==a)return[...a].map(n=>N[n]).join``;
[...a].reverse().map((n,i)=>r=(((n-=0)==1&&i%4||!n)?'': N[n])+M[i%4]+(i%4?r:K[(i/4)|0]+r))
return r;
})
}