From 9bb41b2b0282c2cdd64dc060174a2aba917f6696 Mon Sep 17 00:00:00 2001 From: zichun Date: Wed, 29 Apr 2026 11:10:07 +0800 Subject: [PATCH] chore: plan phase A0~A5 done --- .claude/settings.json | 26 ++++++++++++++++++++++++++ .claude/settings.local.json | 23 +++++++++++++++++++++++ .githooks/pre-push | 9 +++++++++ .gitignore | 32 ++++++++++++++++++++++++++++++++ .obsidian/app.json | 1 + .obsidian/appearance.json | 1 + .obsidian/community-plugins.json | 3 +++ .obsidian/core-plugins.json | 33 +++++++++++++++++++++++++++++++++ .obsidian/plugins/table-editor-obsidian/data.json | 6 ++++++ .obsidian/plugins/table-editor-obsidian/main.js | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .obsidian/plugins/table-editor-obsidian/manifest.json | 15 +++++++++++++++ .obsidian/plugins/table-editor-obsidian/styles.css | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .obsidian/workspace.json | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/01-需求清单/MOD-模块管理/REQ-MOD-001.md | 31 +++++++++++++++++++++++++++++++ docs/01-需求清单/MOD-模块管理/REQ-MOD-002.md | 30 ++++++++++++++++++++++++++++++ docs/01-需求清单/MOD-模块管理/REQ-MOD-003.md | 21 +++++++++++++++++++++ docs/01-需求清单/MOD-模块管理/REQ-MOD-004.md | 32 ++++++++++++++++++++++++++++++++ docs/01-需求清单/MOD-模块管理/_module.md | 5 +++++ docs/01-需求清单/USR-用户管理/REQ-USR-001.md | 41 +++++++++++++++++++++++++++++++++++++++++ docs/01-需求清单/USR-用户管理/REQ-USR-002.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ docs/01-需求清单/USR-用户管理/REQ-USR-003.md | 37 +++++++++++++++++++++++++++++++++++++ docs/01-需求清单/USR-用户管理/REQ-USR-004.md | 21 +++++++++++++++++++++ docs/01-需求清单/USR-用户管理/_module.md | 5 +++++ docs/01-需求清单/index.md | 18 ++++++++++++++++++ docs/02-开发计划.md | 31 +++++++++++++++++++++++++++++++ docs/03-数据库设计文档.md | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/04-技术规范.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/05-API接口契约.md | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/06-UI交互规范.md | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/07-环境配置.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ docs/08-模块任务管理.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/09-项目目录结构.md | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/10-验收检查清单.md | 16 ++++++++++++++++ scripts/setup-test-db.sh | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/test.sh | 29 +++++++++++++++++++++++++++++ sql/migrations/.gitkeep | 0 sql/migrations/V1__initial_schema.sql | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 38 files changed, 2397 insertions(+), 0 deletions(-) create mode 100644 .claude/settings.json create mode 100644 .claude/settings.local.json create mode 100755 .githooks/pre-push create mode 100644 .gitignore create mode 100644 .obsidian/app.json create mode 100644 .obsidian/appearance.json create mode 100644 .obsidian/community-plugins.json create mode 100644 .obsidian/core-plugins.json create mode 100644 .obsidian/plugins/table-editor-obsidian/data.json create mode 100644 .obsidian/plugins/table-editor-obsidian/main.js create mode 100644 .obsidian/plugins/table-editor-obsidian/manifest.json create mode 100644 .obsidian/plugins/table-editor-obsidian/styles.css create mode 100644 .obsidian/workspace.json create mode 100644 CLAUDE.md create mode 100644 docs/01-需求清单/MOD-模块管理/REQ-MOD-001.md create mode 100644 docs/01-需求清单/MOD-模块管理/REQ-MOD-002.md create mode 100644 docs/01-需求清单/MOD-模块管理/REQ-MOD-003.md create mode 100644 docs/01-需求清单/MOD-模块管理/REQ-MOD-004.md create mode 100644 docs/01-需求清单/MOD-模块管理/_module.md create mode 100644 docs/01-需求清单/USR-用户管理/REQ-USR-001.md create mode 100644 docs/01-需求清单/USR-用户管理/REQ-USR-002.md create mode 100644 docs/01-需求清单/USR-用户管理/REQ-USR-003.md create mode 100644 docs/01-需求清单/USR-用户管理/REQ-USR-004.md create mode 100644 docs/01-需求清单/USR-用户管理/_module.md create mode 100644 docs/01-需求清单/index.md create mode 100644 docs/02-开发计划.md create mode 100644 docs/03-数据库设计文档.md create mode 100644 docs/04-技术规范.md create mode 100644 docs/05-API接口契约.md create mode 100644 docs/06-UI交互规范.md create mode 100644 docs/07-环境配置.md create mode 100644 docs/08-模块任务管理.md create mode 100644 docs/09-项目目录结构.md create mode 100644 docs/10-验收检查清单.md create mode 100755 scripts/setup-test-db.sh create mode 100755 scripts/test.sh create mode 100644 sql/migrations/.gitkeep create mode 100644 sql/migrations/V1__initial_schema.sql diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..119ce24 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,26 @@ +{ + "env": { + "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000", + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" + }, + "includeCoAuthoredBy": false, + "permissions": { + "allow": [ + "Bash(git -C *)", + "Bash(curl *)", + "Bash(gunzip *)", + "Bash(conda run *)", + "Bash(conda activate *)", + "Bash(sort *)", + "Bash(git commit *)", + "Bash(git add *)", + "Bash(whois *)", + "Bash(git branch *)", + "Bash(git reset *)", + "Bash(git checkout *)", + "Bash(conda env list)", + "Bash(grep *)" + ], + "defaultMode": "acceptEdits" + } +} diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..93a8ee3 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,23 @@ +{ + "permissions": { + "allow": [ + "Skill(erp-workflow:erp-skeleton-gen)", + "Bash(git init *)", + "Skill(erp-tech-stack-lock)", + "Skill(erp-workflow:erp-tech-stack-lock)", + "Bash(cp \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/erp-skeleton-gen/templates/env-local-template\" .env.local)", + "Bash(cp \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/erp-skeleton-gen/templates/githooks-pre-push-template.sh\" .githooks/pre-push)", + "Bash(cp \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/erp-skeleton-gen/templates/scripts-setup-test-db-template.sh\" scripts/setup-test-db.sh)", + "Bash(cp -n \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/project-init/templates/CLAUDE-template.md\" CLAUDE.md)", + "Bash(cp -n \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/project-init/templates/docs-01-index-template.md\" docs/01-需求清单/index.md)", + "Bash(cp -n \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/project-init/templates/docs-04-stack-template.md\" docs/04-技术规范.md)", + "Bash(cp -n \"/Users/reporkey/Google Drive/My Drive/xly/cc文档/erp-workflow-plugin/skills/plan/project-init/templates/docs-08-initial-template.md\" docs/08-模块任务管理.md)", + "Bash(git --version)", + "Bash(mysql --version)", + "Read(//opt/homebrew/Cellar/mysql-client/9.6.0/bin/**)", + "Read(//usr/local/opt/mysql-client/bin/**)", + "Read(//opt/homebrew/opt/mysql/bin/**)", + "Read(//usr/local/opt/mysql/bin/**)" + ] + } +} diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..8289050 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# .githooks/pre-push — run scripts/test.sh before every push. +# No --no-verify: the claude-code hook deny-no-verify.sh also blocks it. + +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +./scripts/test.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac39aa6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# ==== ERP 插件推荐忽略项(skeleton-gen 追加) ==== +# 本地运行时配置(含真实凭据,严禁入库) +.env.local +.env.*.local + +# Java / Maven +target/ +*.class + +# Node / 前端构建产物 +node_modules/ +dist/ +build/ +coverage/ + +# IDE +.idea/ +.vscode/ +*.iml + +# OS +.DS_Store +Thumbs.db + +# 日志 +*.log +logs/ + +# 插件运行时临时文件 +.tmp/ +*.raw +# ==== 结束 ==== diff --git a/.obsidian/app.json b/.obsidian/app.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.obsidian/app.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/appearance.json b/.obsidian/appearance.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.obsidian/appearance.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/.obsidian/community-plugins.json b/.obsidian/community-plugins.json new file mode 100644 index 0000000..7e0c513 --- /dev/null +++ b/.obsidian/community-plugins.json @@ -0,0 +1,3 @@ +[ + "table-editor-obsidian" +] \ No newline at end of file diff --git a/.obsidian/core-plugins.json b/.obsidian/core-plugins.json new file mode 100644 index 0000000..639b90d --- /dev/null +++ b/.obsidian/core-plugins.json @@ -0,0 +1,33 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": true, + "outgoing-link": true, + "tag-pane": true, + "footnotes": false, + "properties": true, + "page-preview": true, + "daily-notes": true, + "templates": true, + "note-composer": true, + "command-palette": true, + "slash-command": false, + "editor-status": true, + "bookmarks": true, + "markdown-importer": false, + "zk-prefixer": false, + "random-note": false, + "outline": true, + "word-count": true, + "slides": false, + "audio-recorder": false, + "workspaces": false, + "file-recovery": true, + "publish": false, + "sync": true, + "bases": true, + "webviewer": false +} \ No newline at end of file diff --git a/.obsidian/plugins/table-editor-obsidian/data.json b/.obsidian/plugins/table-editor-obsidian/data.json new file mode 100644 index 0000000..9009465 --- /dev/null +++ b/.obsidian/plugins/table-editor-obsidian/data.json @@ -0,0 +1,6 @@ +{ + "formatType": "normal", + "showRibbonIcon": true, + "bindEnter": true, + "bindTab": true +} \ No newline at end of file diff --git a/.obsidian/plugins/table-editor-obsidian/main.js b/.obsidian/plugins/table-editor-obsidian/main.js new file mode 100644 index 0000000..37f76a2 --- /dev/null +++ b/.obsidian/plugins/table-editor-obsidian/main.js @@ -0,0 +1,236 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ + +var c9=Object.create;var x1=Object.defineProperty;var f9=Object.getOwnPropertyDescriptor;var h9=Object.getOwnPropertyNames;var d9=Object.getPrototypeOf,g9=Object.prototype.hasOwnProperty;var we=(s,r)=>()=>(r||s((r={exports:{}}).exports,r),r.exports),p9=(s,r)=>{for(var l in r)x1(s,l,{get:r[l],enumerable:!0})},wl=(s,r,l,c)=>{if(r&&typeof r=="object"||typeof r=="function")for(let d of h9(r))!g9.call(s,d)&&d!==l&&x1(s,d,{get:()=>r[d],enumerable:!(c=f9(r,d))||c.enumerable});return s};var y1=(s,r,l)=>(l=s!=null?c9(d9(s)):{},wl(r||!s||!s.__esModule?x1(l,"default",{value:s,enumerable:!0}):l,s)),m9=s=>wl(x1({},"__esModule",{value:!0}),s);var O1=we(L1=>{"use strict";Object.defineProperty(L1,"__esModule",{value:!0});L1.Point=void 0;var s3=class{constructor(r,l){this.row=r,this.column=l}equals(r){return this.row===r.row&&this.column===r.column}};L1.Point=s3});var P1=we(S1=>{"use strict";Object.defineProperty(S1,"__esModule",{value:!0});S1.Range=void 0;var l3=class{constructor(r,l){this.start=r,this.end=l}};S1.Range=l3});var W1=we(I1=>{"use strict";Object.defineProperty(I1,"__esModule",{value:!0});I1.Focus=void 0;var u3=class s{constructor(r,l,c){this.row=r,this.column=l,this.offset=c}posEquals(r){return this.row===r.row&&this.column===r.column}setRow(r){return new s(r,this.column,this.offset)}setColumn(r){return new s(this.row,r,this.offset)}setOffset(r){return new s(this.row,this.column,r)}};I1.Focus=u3});var vi=we(Dn=>{"use strict";Object.defineProperty(Dn,"__esModule",{value:!0});Dn.HeaderAlignment=Dn.DefaultAlignment=Dn.Alignment=void 0;var _l;(function(s){s.NONE="none",s.LEFT="left",s.RIGHT="right",s.CENTER="center"})(_l||(Dn.Alignment=_l={}));var bl;(function(s){s.LEFT="left",s.RIGHT="right",s.CENTER="center"})(bl||(Dn.DefaultAlignment=bl={}));var El;(function(s){s.FOLLOW="follow",s.LEFT="left",s.RIGHT="right",s.CENTER="center"})(El||(Dn.HeaderAlignment=El={}))});var Pr=we(D1=>{"use strict";Object.defineProperty(D1,"__esModule",{value:!0});D1.TableCell=void 0;var M1=vi(),a3=class{constructor(r){this.rawContent=r,this.content=r.trim(),this.paddingLeft=this.content===""?this.rawContent===""?0:1:this.rawContent.length-this.rawContent.trimLeft().length,this.paddingRight=this.rawContent.length-this.content.length-this.paddingLeft}toText(){return this.rawContent}isDelimiter(){return/^\s*:?-+:?\s*$/.test(this.rawContent)}getAlignment(){if(this.isDelimiter())return this.content[0]===":"?this.content[this.content.length-1]===":"?M1.Alignment.CENTER:M1.Alignment.LEFT:this.content[this.content.length-1]===":"?M1.Alignment.RIGHT:M1.Alignment.NONE}computeContentOffset(r){return this.content===""||r{"use strict";Object.defineProperty(F1,"__esModule",{value:!0});F1.TableRow=void 0;var w9=Pr(),c3=class s{constructor(r,l,c){this._cells=r.slice(),this.marginLeft=l,this.marginRight=c}getWidth(){return this._cells.length}getCells(){return this._cells.slice()}getCellAt(r){return this._cells[r]}setCellAt(r,l){let c=this.getCells();return c[r]=new w9.TableCell(l),new s(c,this.marginLeft,this.marginRight)}toText(){if(this._cells.length===0)return this.marginLeft;let r=this._cells.map(l=>l.toText()).join("|");return`${this.marginLeft}|${r}|${this.marginRight}`}isDelimiter(){return this._cells.every(r=>r.isDelimiter())}};F1.TableRow=c3});var Xt=we(ct=>{"use strict";Object.defineProperty(ct,"__esModule",{value:!0});ct.Err=ct.Ok=ct.err=ct.ok=void 0;var C9=s=>new k1(s);ct.ok=C9;var v9=s=>new U1(s);ct.err=v9;var k1=class{constructor(r){this.value=r,this.match=(l,c)=>l(this.value)}isOk(){return!0}isErr(){return!this.isOk()}map(r){return(0,ct.ok)(r(this.value))}mapErr(r){return(0,ct.ok)(this.value)}andThen(r){return r(this.value)}unwrapOr(r){return this.value}_unsafeUnwrap(){return this.value}_unsafeUnwrapErr(){throw new Error("Called `_unsafeUnwrapErr` on an Ok")}};ct.Ok=k1;var U1=class{constructor(r){this.error=r,this.match=(l,c)=>c(this.error)}isOk(){return!1}isErr(){return!this.isOk()}map(r){return(0,ct.err)(this.error)}mapErr(r){return(0,ct.err)(r(this.error))}andThen(r){return(0,ct.err)(this.error)}unwrapOr(r){return r}_unsafeUnwrap(){throw new Error("Called `_unsafeUnwrap` on an Err")}_unsafeUnwrapErr(){return this.error}};ct.Err=U1});var $t=we(St=>{"use strict";Object.defineProperty(St,"__esModule",{value:!0});St.prettyPrintAST=St.checkChildLength=St.checkType=St.errRelativeReferenceIndex=St.errIndex0=void 0;St.errIndex0=new Error("Index 0 used to create a reference");St.errRelativeReferenceIndex=new Error("Can not use relative reference where absolute reference is required");var _9=(s,...r)=>{if(!(r.indexOf(s.type)>=0))return new Error(`Formula element '${s.text}' is a ${s.type} but expected one of ${r} in this position.`)};St.checkType=_9;var b9=(s,r)=>{if(s.children.length!==r)return new Error(`Formula element '${s.text}' was expected to have ${r} elements, but had ${s.children.length}`)};St.checkChildLength=b9;var E9=(s,r=0)=>{console.log(" ".repeat(r)+`|-${s.type}${s.children.length===0?"="+s.text:""}`),s.children&&s.children.forEach(l=>{(0,St.prettyPrintAST)(l,r+1)})};St.prettyPrintAST=E9});var f3=we((Al,q1)=>{(function(s){"use strict";var r=9e15,l=1e9,c="0123456789abcdef",d="2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058",C="3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789",_={precision:20,rounding:4,modulo:1,toExpNeg:-7,toExpPos:21,minE:-r,maxE:r,crypto:!1},m,A,P,y,S=!0,V="[DecimalError] ",M=V+"Invalid argument: ",Y=V+"Precision limit exceeded",se=V+"crypto unavailable",ge="[object Decimal]",D=Math.floor,$=Math.pow,U=/^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i,K=/^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i,te=/^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i,J=/^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,Q=1e7,G=7,Ce=9007199254740991,Pe=d.length-1,ot=C.length-1,B={toStringTag:ge};B.absoluteValue=B.abs=function(){var o=new this.constructor(this);return o.s<0&&(o.s=1),j(o)},B.ceil=function(){return j(new this.constructor(this),this.e+1,2)},B.clampedTo=B.clamp=function(o,u){var a,f=this,g=f.constructor;if(o=new g(o),u=new g(u),!o.s||!u.s)return new g(NaN);if(o.gt(u))throw Error(M+u);return a=f.cmp(o),a<0?o:f.cmp(u)>0?u:new g(f)},B.comparedTo=B.cmp=function(o){var u,a,f,g,p=this,E=p.d,T=(o=new p.constructor(o)).d,L=p.s,x=o.s;if(!E||!T)return!L||!x?NaN:L!==x?L:E===T?0:!E^L<0?1:-1;if(!E[0]||!T[0])return E[0]?L:T[0]?-x:0;if(L!==x)return L;if(p.e!==o.e)return p.e>o.e^L<0?1:-1;for(f=E.length,g=T.length,u=0,a=fT[u]^L<0?1:-1;return f===g?0:f>g^L<0?1:-1},B.cosine=B.cos=function(){var o,u,a=this,f=a.constructor;return a.d?a.d[0]?(o=f.precision,u=f.rounding,f.precision=o+Math.max(a.e,a.sd())+G,f.rounding=1,a=Lo(f,Fi(f,a)),f.precision=o,f.rounding=u,j(y==2||y==3?a.neg():a,o,u,!0)):new f(1):new f(NaN)},B.cubeRoot=B.cbrt=function(){var o,u,a,f,g,p,E,T,L,x,I=this,F=I.constructor;if(!I.isFinite()||I.isZero())return new F(I);for(S=!1,p=I.s*$(I.s*I,1/3),!p||Math.abs(p)==1/0?(a=Oe(I.d),o=I.e,(p=(o-a.length+1)%3)&&(a+=p==1||p==-2?"0":"00"),p=$(a,1/3),o=D((o+1)/3)-(o%3==(o<0?-1:2)),p==1/0?a="5e"+o:(a=p.toExponential(),a=a.slice(0,a.indexOf("e")+1)+o),f=new F(a),f.s=I.s):f=new F(p.toString()),E=(o=F.precision)+3;;)if(T=f,L=T.times(T).times(T),x=L.plus(I),f=Ae(x.plus(I).times(T),x.plus(L),E+2,1),Oe(T.d).slice(0,E)===(a=Oe(f.d)).slice(0,E))if(a=a.slice(E-3,E+1),a=="9999"||!g&&a=="4999"){if(!g&&(j(T,o+1,0),T.times(T).times(T).eq(I))){f=T;break}E+=4,g=1}else{(!+a||!+a.slice(1)&&a.charAt(0)=="5")&&(j(f,o+1,1),u=!f.times(f).times(f).eq(I));break}return S=!0,j(f,o,F.rounding,u)},B.decimalPlaces=B.dp=function(){var o,u=this.d,a=NaN;if(u){if(o=u.length-1,a=(o-D(this.e/G))*G,o=u[o],o)for(;o%10==0;o/=10)a--;a<0&&(a=0)}return a},B.dividedBy=B.div=function(o){return Ae(this,new this.constructor(o))},B.dividedToIntegerBy=B.divToInt=function(o){var u=this,a=u.constructor;return j(Ae(u,new a(o),0,1,1),a.precision,a.rounding)},B.equals=B.eq=function(o){return this.cmp(o)===0},B.floor=function(){return j(new this.constructor(this),this.e+1,3)},B.greaterThan=B.gt=function(o){return this.cmp(o)>0},B.greaterThanOrEqualTo=B.gte=function(o){var u=this.cmp(o);return u==1||u===0},B.hyperbolicCosine=B.cosh=function(){var o,u,a,f,g,p=this,E=p.constructor,T=new E(1);if(!p.isFinite())return new E(p.s?1/0:NaN);if(p.isZero())return T;a=E.precision,f=E.rounding,E.precision=a+Math.max(p.e,p.sd())+4,E.rounding=1,g=p.d.length,g<32?(o=Math.ceil(g/3),u=(1/Zn(4,o)).toString()):(o=16,u="2.3283064365386962890625e-10"),p=et(E,1,p.times(u),new E(1),!0);for(var L,x=o,I=new E(8);x--;)L=p.times(p),p=T.minus(L.times(I.minus(L.times(I))));return j(p,E.precision=a,E.rounding=f,!0)},B.hyperbolicSine=B.sinh=function(){var o,u,a,f,g=this,p=g.constructor;if(!g.isFinite()||g.isZero())return new p(g);if(u=p.precision,a=p.rounding,p.precision=u+Math.max(g.e,g.sd())+4,p.rounding=1,f=g.d.length,f<3)g=et(p,2,g,g,!0);else{o=1.4*Math.sqrt(f),o=o>16?16:o|0,g=g.times(1/Zn(5,o)),g=et(p,2,g,g,!0);for(var E,T=new p(5),L=new p(16),x=new p(20);o--;)E=g.times(g),g=g.times(T.plus(E.times(L.times(E).plus(x))))}return p.precision=u,p.rounding=a,j(g,u,a,!0)},B.hyperbolicTangent=B.tanh=function(){var o,u,a=this,f=a.constructor;return a.isFinite()?a.isZero()?new f(a):(o=f.precision,u=f.rounding,f.precision=o+7,f.rounding=1,Ae(a.sinh(),a.cosh(),f.precision=o,f.rounding=u)):new f(a.s)},B.inverseCosine=B.acos=function(){var o,u=this,a=u.constructor,f=u.abs().cmp(1),g=a.precision,p=a.rounding;return f!==-1?f===0?u.isNeg()?Ze(a,g,p):new a(0):new a(NaN):u.isZero()?Ze(a,g+4,p).times(.5):(a.precision=g+6,a.rounding=1,u=u.asin(),o=Ze(a,g+4,p).times(.5),a.precision=g,a.rounding=p,o.minus(u))},B.inverseHyperbolicCosine=B.acosh=function(){var o,u,a=this,f=a.constructor;return a.lte(1)?new f(a.eq(1)?0:NaN):a.isFinite()?(o=f.precision,u=f.rounding,f.precision=o+Math.max(Math.abs(a.e),a.sd())+4,f.rounding=1,S=!1,a=a.times(a).minus(1).sqrt().plus(a),S=!0,f.precision=o,f.rounding=u,a.ln()):new f(a)},B.inverseHyperbolicSine=B.asinh=function(){var o,u,a=this,f=a.constructor;return!a.isFinite()||a.isZero()?new f(a):(o=f.precision,u=f.rounding,f.precision=o+2*Math.max(Math.abs(a.e),a.sd())+6,f.rounding=1,S=!1,a=a.times(a).plus(1).sqrt().plus(a),S=!0,f.precision=o,f.rounding=u,a.ln())},B.inverseHyperbolicTangent=B.atanh=function(){var o,u,a,f,g=this,p=g.constructor;return g.isFinite()?g.e>=0?new p(g.abs().eq(1)?g.s/0:g.isZero()?g:NaN):(o=p.precision,u=p.rounding,f=g.sd(),Math.max(f,o)<2*-g.e-1?j(new p(g),o,u,!0):(p.precision=a=f-g.e,g=Ae(g.plus(1),new p(1).minus(g),a+o,1),p.precision=o+4,p.rounding=1,g=g.ln(),p.precision=o,p.rounding=u,g.times(.5))):new p(NaN)},B.inverseSine=B.asin=function(){var o,u,a,f,g=this,p=g.constructor;return g.isZero()?new p(g):(u=g.abs().cmp(1),a=p.precision,f=p.rounding,u!==-1?u===0?(o=Ze(p,a+4,f).times(.5),o.s=g.s,o):new p(NaN):(p.precision=a+6,p.rounding=1,g=g.div(new p(1).minus(g.times(g)).sqrt().plus(1)).atan(),p.precision=a,p.rounding=f,g.times(2)))},B.inverseTangent=B.atan=function(){var o,u,a,f,g,p,E,T,L,x=this,I=x.constructor,F=I.precision,z=I.rounding;if(x.isFinite()){if(x.isZero())return new I(x);if(x.abs().eq(1)&&F+4<=ot)return E=Ze(I,F+4,z).times(.25),E.s=x.s,E}else{if(!x.s)return new I(NaN);if(F+4<=ot)return E=Ze(I,F+4,z).times(.5),E.s=x.s,E}for(I.precision=T=F+10,I.rounding=1,a=Math.min(28,T/G+2|0),o=a;o;--o)x=x.div(x.times(x).plus(1).sqrt().plus(1));for(S=!1,u=Math.ceil(T/G),f=1,L=x.times(x),E=new I(x),g=x;o!==-1;)if(g=g.times(L),p=E.minus(g.div(f+=2)),g=g.times(L),E=p.plus(g.div(f+=2)),E.d[u]!==void 0)for(o=u;E.d[o]===p.d[o]&&o--;);return a&&(E=E.times(2<this.d.length-2},B.isNaN=function(){return!this.s},B.isNegative=B.isNeg=function(){return this.s<0},B.isPositive=B.isPos=function(){return this.s>0},B.isZero=function(){return!!this.d&&this.d[0]===0},B.lessThan=B.lt=function(o){return this.cmp(o)<0},B.lessThanOrEqualTo=B.lte=function(o){return this.cmp(o)<1},B.logarithm=B.log=function(o){var u,a,f,g,p,E,T,L,x=this,I=x.constructor,F=I.precision,z=I.rounding,ie=5;if(o==null)o=new I(10),u=!0;else{if(o=new I(o),a=o.d,o.s<0||!a||!a[0]||o.eq(1))return new I(NaN);u=o.eq(10)}if(a=x.d,x.s<0||!a||!a[0]||x.eq(1))return new I(a&&!a[0]?-1/0:x.s!=1?NaN:a?0:1/0);if(u)if(a.length>1)p=!0;else{for(g=a[0];g%10===0;)g/=10;p=g!==1}if(S=!1,T=F+ie,E=bt(x,T),f=u?pr(I,T+10):bt(o,T),L=Ae(E,f,T,1),vt(L.d,g=F,z))do if(T+=10,E=bt(x,T),f=u?pr(I,T+10):bt(o,T),L=Ae(E,f,T,1),!p){+Oe(L.d).slice(g+1,g+15)+1==1e14&&(L=j(L,F+1,0));break}while(vt(L.d,g+=10,z));return S=!0,j(L,F,z)},B.minus=B.sub=function(o){var u,a,f,g,p,E,T,L,x,I,F,z,ie=this,_e=ie.constructor;if(o=new _e(o),!ie.d||!o.d)return!ie.s||!o.s?o=new _e(NaN):ie.d?o.s=-o.s:o=new _e(o.d||ie.s!==o.s?ie:NaN),o;if(ie.s!=o.s)return o.s=-o.s,ie.plus(o);if(x=ie.d,z=o.d,T=_e.precision,L=_e.rounding,!x[0]||!z[0]){if(z[0])o.s=-o.s;else if(x[0])o=new _e(ie);else return new _e(L===3?-0:0);return S?j(o,T,L):o}if(a=D(o.e/G),I=D(ie.e/G),x=x.slice(),p=I-a,p){for(F=p<0,F?(u=x,p=-p,E=z.length):(u=z,a=I,E=x.length),f=Math.max(Math.ceil(T/G),E)+2,p>f&&(p=f,u.length=1),u.reverse(),f=p;f--;)u.push(0);u.reverse()}else{for(f=x.length,E=z.length,F=f0;--f)x[E++]=0;for(f=z.length;f>p;){if(x[--f]E?p+1:E+1,g>E&&(g=E,a.length=1),a.reverse();g--;)a.push(0);a.reverse()}for(E=x.length,g=I.length,E-g<0&&(g=E,a=I,I=x,x=a),u=0;g;)u=(x[--g]=x[g]+I[g]+u)/Q|0,x[g]%=Q;for(u&&(x.unshift(u),++f),E=x.length;x[--E]==0;)x.pop();return o.d=x,o.e=gr(x,f),S?j(o,T,L):o},B.precision=B.sd=function(o){var u,a=this;if(o!==void 0&&o!==!!o&&o!==1&&o!==0)throw Error(M+o);return a.d?(u=zn(a.d),o&&a.e+1>u&&(u=a.e+1)):u=NaN,u},B.round=function(){var o=this,u=o.constructor;return j(new u(o),o.e+1,u.rounding)},B.sine=B.sin=function(){var o,u,a=this,f=a.constructor;return a.isFinite()?a.isZero()?new f(a):(o=f.precision,u=f.rounding,f.precision=o+Math.max(a.e,a.sd())+G,f.rounding=1,a=Oo(f,Fi(f,a)),f.precision=o,f.rounding=u,j(y>2?a.neg():a,o,u,!0)):new f(NaN)},B.squareRoot=B.sqrt=function(){var o,u,a,f,g,p,E=this,T=E.d,L=E.e,x=E.s,I=E.constructor;if(x!==1||!T||!T[0])return new I(!x||x<0&&(!T||T[0])?NaN:T?E:1/0);for(S=!1,x=Math.sqrt(+E),x==0||x==1/0?(u=Oe(T),(u.length+L)%2==0&&(u+="0"),x=Math.sqrt(u),L=D((L+1)/2)-(L<0||L%2),x==1/0?u="5e"+L:(u=x.toExponential(),u=u.slice(0,u.indexOf("e")+1)+L),f=new I(u)):f=new I(x.toString()),a=(L=I.precision)+3;;)if(p=f,f=p.plus(Ae(E,p,a+2,1)).times(.5),Oe(p.d).slice(0,a)===(u=Oe(f.d)).slice(0,a))if(u=u.slice(a-3,a+1),u=="9999"||!g&&u=="4999"){if(!g&&(j(p,L+1,0),p.times(p).eq(E))){f=p;break}a+=4,g=1}else{(!+u||!+u.slice(1)&&u.charAt(0)=="5")&&(j(f,L+1,1),o=!f.times(f).eq(E));break}return S=!0,j(f,L,I.rounding,o)},B.tangent=B.tan=function(){var o,u,a=this,f=a.constructor;return a.isFinite()?a.isZero()?new f(a):(o=f.precision,u=f.rounding,f.precision=o+10,f.rounding=1,a=a.sin(),a.s=1,a=Ae(a,new f(1).minus(a.times(a)).sqrt(),o+10,0),f.precision=o,f.rounding=u,j(y==2||y==4?a.neg():a,o,u,!0)):new f(NaN)},B.times=B.mul=function(o){var u,a,f,g,p,E,T,L,x,I=this,F=I.constructor,z=I.d,ie=(o=new F(o)).d;if(o.s*=I.s,!z||!z[0]||!ie||!ie[0])return new F(!o.s||z&&!z[0]&&!ie||ie&&!ie[0]&&!z?NaN:!z||!ie?o.s/0:o.s*0);for(a=D(I.e/G)+D(o.e/G),L=z.length,x=ie.length,L=0;){for(u=0,g=L+f;g>f;)T=p[g]+ie[f]*z[g-f-1]+u,p[g--]=T%Q|0,u=T/Q|0;p[g]=(p[g]+u)%Q|0}for(;!p[--E];)p.pop();return u?++a:p.shift(),o.d=p,o.e=gr(p,a),S?j(o,F.precision,F.rounding):o},B.toBinary=function(o,u){return cn(this,2,o,u)},B.toDecimalPlaces=B.toDP=function(o,u){var a=this,f=a.constructor;return a=new f(a),o===void 0?a:(je(o,0,l),u===void 0?u=f.rounding:je(u,0,8),j(a,o+a.e+1,u))},B.toExponential=function(o,u){var a,f=this,g=f.constructor;return o===void 0?a=Mt(f,!0):(je(o,0,l),u===void 0?u=g.rounding:je(u,0,8),f=j(new g(f),o+1,u),a=Mt(f,!0,o+1)),f.isNeg()&&!f.isZero()?"-"+a:a},B.toFixed=function(o,u){var a,f,g=this,p=g.constructor;return o===void 0?a=Mt(g):(je(o,0,l),u===void 0?u=p.rounding:je(u,0,8),f=j(new p(g),o+g.e+1,u),a=Mt(f,!1,o+f.e+1)),g.isNeg()&&!g.isZero()?"-"+a:a},B.toFraction=function(o){var u,a,f,g,p,E,T,L,x,I,F,z,ie=this,_e=ie.d,ce=ie.constructor;if(!_e)return new ce(ie);if(x=a=new ce(1),f=L=new ce(0),u=new ce(f),p=u.e=zn(_e)-ie.e-1,E=p%G,u.d[0]=$(10,E<0?G+E:E),o==null)o=p>0?u:x;else{if(T=new ce(o),!T.isInt()||T.lt(x))throw Error(M+T);o=T.gt(u)?p>0?u:x:T}for(S=!1,T=new ce(Oe(_e)),I=ce.precision,ce.precision=p=_e.length*G*2;F=Ae(T,u,0,1,1),g=a.plus(F.times(f)),g.cmp(o)!=1;)a=f,f=g,g=x,x=L.plus(F.times(g)),L=g,g=u,u=T.minus(F.times(g)),T=g;return g=Ae(o.minus(a),f,0,1,1),L=L.plus(g.times(x)),a=a.plus(g.times(f)),L.s=x.s=ie.s,z=Ae(x,f,p,1).minus(ie).abs().cmp(Ae(L,a,p,1).minus(ie).abs())<1?[x,f]:[L,a],ce.precision=I,S=!0,z},B.toHexadecimal=B.toHex=function(o,u){return cn(this,16,o,u)},B.toNearest=function(o,u){var a=this,f=a.constructor;if(a=new f(a),o==null){if(!a.d)return a;o=new f(1),u=f.rounding}else{if(o=new f(o),u===void 0?u=f.rounding:je(u,0,8),!a.d)return o.s?a:o;if(!o.d)return o.s&&(o.s=a.s),o}return o.d[0]?(S=!1,a=Ae(a,o,0,u,1).times(o),S=!0,j(a)):(o.s=a.s,a=o),a},B.toNumber=function(){return+this},B.toOctal=function(o,u){return cn(this,8,o,u)},B.toPower=B.pow=function(o){var u,a,f,g,p,E,T=this,L=T.constructor,x=+(o=new L(o));if(!T.d||!o.d||!T.d[0]||!o.d[0])return new L($(+T,x));if(T=new L(T),T.eq(1))return T;if(f=L.precision,p=L.rounding,o.eq(1))return j(T,f,p);if(u=D(o.e/G),u>=o.d.length-1&&(a=x<0?-x:x)<=Ce)return g=En(L,T,a,f),o.s<0?new L(1).div(g):j(g,f,p);if(E=T.s,E<0){if(uL.maxE+1||u0?E/0:0):(S=!1,L.rounding=T.s=1,a=Math.min(12,(u+"").length),g=Tn(o.times(bt(T,f+a)),f),g.d&&(g=j(g,f+5,1),vt(g.d,f,p)&&(u=f+10,g=j(Tn(o.times(bt(T,u+a)),u),u+5,1),+Oe(g.d).slice(f+1,f+15)+1==1e14&&(g=j(g,f+1,0)))),g.s=E,S=!0,L.rounding=p,j(g,f,p))},B.toPrecision=function(o,u){var a,f=this,g=f.constructor;return o===void 0?a=Mt(f,f.e<=g.toExpNeg||f.e>=g.toExpPos):(je(o,1,l),u===void 0?u=g.rounding:je(u,0,8),f=j(new g(f),o,u),a=Mt(f,o<=f.e||f.e<=g.toExpNeg,o)),f.isNeg()&&!f.isZero()?"-"+a:a},B.toSignificantDigits=B.toSD=function(o,u){var a=this,f=a.constructor;return o===void 0?(o=f.precision,u=f.rounding):(je(o,1,l),u===void 0?u=f.rounding:je(u,0,8)),j(new f(a),o,u)},B.toString=function(){var o=this,u=o.constructor,a=Mt(o,o.e<=u.toExpNeg||o.e>=u.toExpPos);return o.isNeg()&&!o.isZero()?"-"+a:a},B.truncated=B.trunc=function(){return j(new this.constructor(this),this.e+1,1)},B.valueOf=B.toJSON=function(){var o=this,u=o.constructor,a=Mt(o,o.e<=u.toExpNeg||o.e>=u.toExpPos);return o.isNeg()?"-"+a:a};function Oe(o){var u,a,f,g=o.length-1,p="",E=o[0];if(g>0){for(p+=E,u=1;ua)throw Error(M+o)}function vt(o,u,a,f){var g,p,E,T;for(p=o[0];p>=10;p/=10)--u;return--u<0?(u+=G,g=0):(g=Math.ceil((u+1)/G),u%=G),p=$(10,G-u),T=o[g]%p|0,f==null?u<3?(u==0?T=T/100|0:u==1&&(T=T/10|0),E=a<4&&T==99999||a>3&&T==49999||T==5e4||T==0):E=(a<4&&T+1==p||a>3&&T+1==p/2)&&(o[g+1]/p/100|0)==$(10,u-2)-1||(T==p/2||T==0)&&(o[g+1]/p/100|0)==0:u<4?(u==0?T=T/1e3|0:u==1?T=T/100|0:u==2&&(T=T/10|0),E=(f||a<4)&&T==9999||!f&&a>3&&T==4999):E=((f||a<4)&&T+1==p||!f&&a>3&&T+1==p/2)&&(o[g+1]/p/1e3|0)==$(10,u-3)-1,E}function _t(o,u,a){for(var f,g=[0],p,E=0,T=o.length;Ea-1&&(g[f+1]===void 0&&(g[f+1]=0),g[f+1]+=g[f]/a|0,g[f]%=a)}return g.reverse()}function Lo(o,u){var a,f,g;if(u.isZero())return u;f=u.d.length,f<32?(a=Math.ceil(f/3),g=(1/Zn(4,a)).toString()):(a=16,g="2.3283064365386962890625e-10"),o.precision+=a,u=et(o,1,u.times(g),new o(1));for(var p=a;p--;){var E=u.times(u);u=E.times(E).minus(E).times(8).plus(1)}return o.precision-=a,u}var Ae=function(){function o(f,g,p){var E,T=0,L=f.length;for(f=f.slice();L--;)E=f[L]*g+T,f[L]=E%p|0,T=E/p|0;return T&&f.unshift(T),f}function u(f,g,p,E){var T,L;if(p!=E)L=p>E?1:-1;else for(T=L=0;Tg[T]?1:-1;break}return L}function a(f,g,p,E){for(var T=0;p--;)f[p]-=T,T=f[p]1;)f.shift()}return function(f,g,p,E,T,L){var x,I,F,z,ie,_e,ce,Ye,Me,Et,Re,Be,Yn,At,ri,Jn,nn,Cr,Tt,Xn,Qn=f.constructor,jn=f.s==g.s?1:-1,Ge=f.d,ye=g.d;if(!Ge||!Ge[0]||!ye||!ye[0])return new Qn(!f.s||!g.s||(Ge?ye&&Ge[0]==ye[0]:!ye)?NaN:Ge&&Ge[0]==0||!ye?jn*0:jn/0);for(L?(ie=1,I=f.e-g.e):(L=Q,ie=G,I=D(f.e/ie)-D(g.e/ie)),Tt=ye.length,nn=Ge.length,Me=new Qn(jn),Et=Me.d=[],F=0;ye[F]==(Ge[F]||0);F++);if(ye[F]>(Ge[F]||0)&&I--,p==null?(At=p=Qn.precision,E=Qn.rounding):T?At=p+(f.e-g.e)+1:At=p,At<0)Et.push(1),_e=!0;else{if(At=At/ie+2|0,F=0,Tt==1){for(z=0,ye=ye[0],At++;(F1&&(ye=o(ye,z,L),Ge=o(Ge,z,L),Tt=ye.length,nn=Ge.length),Jn=Tt,Re=Ge.slice(0,Tt),Be=Re.length;Be=L/2&&++Cr;do z=0,x=u(ye,Re,Tt,Be),x<0?(Yn=Re[0],Tt!=Be&&(Yn=Yn*L+(Re[1]||0)),z=Yn/Cr|0,z>1?(z>=L&&(z=L-1),ce=o(ye,z,L),Ye=ce.length,Be=Re.length,x=u(ce,Re,Ye,Be),x==1&&(z--,a(ce,Tt=10;z/=10)F++;Me.e=F+I*ie-1,j(Me,T?p+Me.e+1:p,E,_e)}return Me}}();function j(o,u,a,f){var g,p,E,T,L,x,I,F,z,ie=o.constructor;e:if(u!=null){if(F=o.d,!F)return o;for(g=1,T=F[0];T>=10;T/=10)g++;if(p=u-g,p<0)p+=G,E=u,I=F[z=0],L=I/$(10,g-E-1)%10|0;else if(z=Math.ceil((p+1)/G),T=F.length,z>=T)if(f){for(;T++<=z;)F.push(0);I=L=0,g=1,p%=G,E=p-G+1}else break e;else{for(I=T=F[z],g=1;T>=10;T/=10)g++;p%=G,E=p-G+g,L=E<0?0:I/$(10,g-E-1)%10|0}if(f=f||u<0||F[z+1]!==void 0||(E<0?I:I%$(10,g-E-1)),x=a<4?(L||f)&&(a==0||a==(o.s<0?3:2)):L>5||L==5&&(a==4||f||a==6&&(p>0?E>0?I/$(10,g-E):0:F[z-1])%10&1||a==(o.s<0?8:7)),u<1||!F[0])return F.length=0,x?(u-=o.e+1,F[0]=$(10,(G-u%G)%G),o.e=-u||0):F[0]=o.e=0,o;if(p==0?(F.length=z,T=1,z--):(F.length=z+1,T=$(10,G-p),F[z]=E>0?(I/$(10,g-E)%$(10,E)|0)*T:0),x)for(;;)if(z==0){for(p=1,E=F[0];E>=10;E/=10)p++;for(E=F[0]+=T,T=1;E>=10;E/=10)T++;p!=T&&(o.e++,F[0]==Q&&(F[0]=1));break}else{if(F[z]+=T,F[z]!=Q)break;F[z--]=0,T=1}for(p=F.length;F[--p]===0;)F.pop()}return S&&(o.e>ie.maxE?(o.d=null,o.e=NaN):o.e0?p=p.charAt(0)+"."+p.slice(1)+tn(f):E>1&&(p=p.charAt(0)+"."+p.slice(1)),p=p+(o.e<0?"e":"e+")+o.e):g<0?(p="0."+tn(-g-1)+p,a&&(f=a-E)>0&&(p+=tn(f))):g>=E?(p+=tn(g+1-E),a&&(f=a-g-1)>0&&(p=p+"."+tn(f))):((f=g+1)0&&(g+1===E&&(p+="."),p+=tn(f))),p}function gr(o,u){var a=o[0];for(u*=G;a>=10;a/=10)u++;return u}function pr(o,u,a){if(u>Pe)throw S=!0,a&&(o.precision=a),Error(Y);return j(new o(d),u,1,!0)}function Ze(o,u,a){if(u>ot)throw Error(Y);return j(new o(C),u,a,!0)}function zn(o){var u=o.length-1,a=u*G+1;if(u=o[u],u){for(;u%10==0;u/=10)a--;for(u=o[0];u>=10;u/=10)a++}return a}function tn(o){for(var u="";o--;)u+="0";return u}function En(o,u,a,f){var g,p=new o(1),E=Math.ceil(f/G+4);for(S=!1;;){if(a%2&&(p=p.times(u),ht(p.d,E)&&(g=!0)),a=D(a/2),a===0){a=p.d.length-1,g&&p.d[a]===0&&++p.d[a];break}u=u.times(u),ht(u.d,E)}return S=!0,p}function An(o){return o.d[o.d.length-1]&1}function Di(o,u,a){for(var f,g=new o(u[0]),p=0;++p17)return new z(o.d?o.d[0]?o.s<0?0:1/0:1:o.s?o.s<0?0:o:NaN);for(u==null?(S=!1,L=_e):L=u,T=new z(.03125);o.e>-2;)o=o.times(T),F+=5;for(f=Math.log($(2,F))/Math.LN10*2+5|0,L+=f,a=p=E=new z(1),z.precision=L;;){if(p=j(p.times(o),L,1),a=a.times(++I),T=E.plus(Ae(p,a,L,1)),Oe(T.d).slice(0,L)===Oe(E.d).slice(0,L)){for(g=F;g--;)E=j(E.times(E),L,1);if(u==null)if(x<3&&vt(E.d,L-f,ie,x))z.precision=L+=10,a=p=T=new z(1),I=0,x++;else return j(E,z.precision=_e,ie,S=!0);else return z.precision=_e,E}E=T}}function bt(o,u){var a,f,g,p,E,T,L,x,I,F,z,ie=1,_e=10,ce=o,Ye=ce.d,Me=ce.constructor,Et=Me.rounding,Re=Me.precision;if(ce.s<0||!Ye||!Ye[0]||!ce.e&&Ye[0]==1&&Ye.length==1)return new Me(Ye&&!Ye[0]?-1/0:ce.s!=1?NaN:Ye?0:ce);if(u==null?(S=!1,I=Re):I=u,Me.precision=I+=_e,a=Oe(Ye),f=a.charAt(0),Math.abs(p=ce.e)<15e14){for(;f<7&&f!=1||f==1&&a.charAt(1)>3;)ce=ce.times(o),a=Oe(ce.d),f=a.charAt(0),ie++;p=ce.e,f>1?(ce=new Me("0."+a),p++):ce=new Me(f+"."+a.slice(1))}else return x=pr(Me,I+2,Re).times(p+""),ce=bt(new Me(f+"."+a.slice(1)),I-_e).plus(x),Me.precision=Re,u==null?j(ce,Re,Et,S=!0):ce;for(F=ce,L=E=ce=Ae(ce.minus(1),ce.plus(1),I,1),z=j(ce.times(ce),I,1),g=3;;){if(E=j(E.times(z),I,1),x=L.plus(Ae(E,new Me(g),I,1)),Oe(x.d).slice(0,I)===Oe(L.d).slice(0,I))if(L=L.times(2),p!==0&&(L=L.plus(pr(Me,I+2,Re).times(p+""))),L=Ae(L,new Me(ie),I,1),u==null)if(vt(L.d,I-_e,Et,T))Me.precision=I+=_e,x=E=ce=Ae(F.minus(1),F.plus(1),I,1),z=j(ce.times(ce),I,1),g=T=1;else return j(L,Me.precision=Re,Et,S=!0);else return Me.precision=Re,L;L=x,g+=2}}function Zr(o){return String(o.s*o.s/0)}function st(o,u){var a,f,g;for((a=u.indexOf("."))>-1&&(u=u.replace(".","")),(f=u.search(/e/i))>0?(a<0&&(a=f),a+=+u.slice(f+1),u=u.substring(0,f)):a<0&&(a=u.length),f=0;u.charCodeAt(f)===48;f++);for(g=u.length;u.charCodeAt(g-1)===48;--g);if(u=u.slice(f,g),u){if(g-=f,o.e=a=a-f-1,o.d=[],f=(a+1)%G,a<0&&(f+=G),fo.constructor.maxE?(o.d=null,o.e=NaN):o.e-1){if(u=u.replace(/(\d)_(?=\d)/g,"$1"),J.test(u))return st(o,u)}else if(u==="Infinity"||u==="NaN")return+u||(o.s=NaN),o.e=NaN,o.d=null,o;if(K.test(u))a=16,u=u.toLowerCase();else if(U.test(u))a=2;else if(te.test(u))a=8;else throw Error(M+u);for(p=u.search(/p/i),p>0?(L=+u.slice(p+1),u=u.substring(2,p)):u=u.slice(2),p=u.indexOf("."),E=p>=0,f=o.constructor,E&&(u=u.replace(".",""),T=u.length,p=T-p,g=En(f,new f(a),p,p*2)),x=_t(u,a,Q),I=x.length-1,p=I;x[p]===0;--p)x.pop();return p<0?new f(o.s*0):(o.e=gr(x,I),o.d=x,S=!1,E&&(o=Ae(o,g,T*4)),L&&(o=o.times(Math.abs(L)<54?$(2,L):m.pow(2,L))),S=!0,o)}function Oo(o,u){var a,f=u.d.length;if(f<3)return u.isZero()?u:et(o,2,u,u);a=1.4*Math.sqrt(f),a=a>16?16:a|0,u=u.times(1/Zn(5,a)),u=et(o,2,u,u);for(var g,p=new o(5),E=new o(16),T=new o(20);a--;)g=u.times(u),u=u.times(p.plus(g.times(E.times(g).minus(T))));return u}function et(o,u,a,f,g){var p,E,T,L,x=1,I=o.precision,F=Math.ceil(I/G);for(S=!1,L=a.times(a),T=new o(f);;){if(E=Ae(T.times(L),new o(u++*u++),I,1),T=g?f.plus(E):f.minus(E),f=Ae(E.times(L),new o(u++*u++),I,1),E=T.plus(f),E.d[F]!==void 0){for(p=F;E.d[p]===T.d[p]&&p--;);if(p==-1)break}p=T,T=f,f=E,E=p,x++}return S=!0,E.d.length=F+1,E}function Zn(o,u){for(var a=o;--u;)a*=o;return a}function Fi(o,u){var a,f=u.s<0,g=Ze(o,o.precision,1),p=g.times(.5);if(u=u.abs(),u.lte(p))return y=f?4:1,u;if(a=u.divToInt(g),a.isZero())y=f?3:2;else{if(u=u.minus(a.times(g)),u.lte(p))return y=An(a)?f?2:3:f?4:1,u;y=An(a)?f?1:4:f?3:2}return u.minus(g).abs()}function cn(o,u,a,f){var g,p,E,T,L,x,I,F,z,ie=o.constructor,_e=a!==void 0;if(_e?(je(a,1,l),f===void 0?f=ie.rounding:je(f,0,8)):(a=ie.precision,f=ie.rounding),!o.isFinite())I=Zr(o);else{for(I=Mt(o),E=I.indexOf("."),_e?(g=2,u==16?a=a*4-3:u==8&&(a=a*3-2)):g=u,E>=0&&(I=I.replace(".",""),z=new ie(1),z.e=I.length-E,z.d=_t(Mt(z),10,g),z.e=z.d.length),F=_t(I,10,g),p=L=F.length;F[--L]==0;)F.pop();if(!F[0])I=_e?"0p+0":"0";else{if(E<0?p--:(o=new ie(o),o.d=F,o.e=p,o=Ae(o,z,a,f,0,g),F=o.d,p=o.e,x=A),E=F[a],T=g/2,x=x||F[a+1]!==void 0,x=f<4?(E!==void 0||x)&&(f===0||f===(o.s<0?3:2)):E>T||E===T&&(f===4||x||f===6&&F[a-1]&1||f===(o.s<0?8:7)),F.length=a,x)for(;++F[--a]>g-1;)F[a]=0,a||(++p,F.unshift(1));for(L=F.length;!F[L-1];--L);for(E=0,I="";E1)if(u==16||u==8){for(E=u==16?4:3,--L;L%E;L++)I+="0";for(F=_t(I,g,u),L=F.length;!F[L-1];--L);for(E=1,I="1.";EL)for(p-=L;p--;)I+="0";else pu)return o.length=u,!0}function Gn(o){return new this(o).abs()}function mr(o){return new this(o).acos()}function So(o){return new this(o).acosh()}function Vn(o,u){return new this(o).plus(u)}function Po(o){return new this(o).asin()}function Kn(o){return new this(o).asinh()}function Rn(o){return new this(o).atan()}function Gr(o){return new this(o).atanh()}function Vr(o,u){o=new this(o),u=new this(u);var a,f=this.precision,g=this.rounding,p=f+4;return!o.s||!u.s?a=new this(NaN):!o.d&&!u.d?(a=Ze(this,p,1).times(u.s>0?.25:.75),a.s=o.s):!u.d||o.isZero()?(a=u.s<0?Ze(this,f,g):new this(0),a.s=o.s):!o.d||u.isZero()?(a=Ze(this,p,1).times(.5),a.s=o.s):u.s<0?(this.precision=p,this.rounding=1,a=this.atan(Ae(o,u,p,1)),u=Ze(this,p,1),this.precision=f,this.rounding=g,a=o.s<0?a.minus(u):a.plus(u)):a=this.atan(Ae(o,u,p,1)),a}function Kr(o){return new this(o).cbrt()}function Yr(o){return j(o=new this(o),o.e+1,2)}function Jr(o,u,a){return new this(o).clamp(u,a)}function Xr(o){if(!o||typeof o!="object")throw Error(V+"Object expected");var u,a,f,g=o.defaults===!0,p=["precision",1,l,"rounding",0,8,"toExpNeg",-r,0,"toExpPos",0,r,"maxE",0,r,"minE",-r,0,"modulo",0,9];for(u=0;u=p[u+1]&&f<=p[u+2])this[a]=f;else throw Error(M+a+": "+f);if(a="crypto",g&&(this[a]=_[a]),(f=o[a])!==void 0)if(f===!0||f===!1||f===0||f===1)if(f)if(typeof crypto!="undefined"&&crypto&&(crypto.getRandomValues||crypto.randomBytes))this[a]=!0;else throw Error(se);else this[a]=!1;else throw Error(M+a+": "+f);return this}function Qr(o){return new this(o).cos()}function jr(o){return new this(o).cosh()}function wr(o){var u,a,f;function g(p){var E,T,L,x=this;if(!(x instanceof g))return new g(p);if(x.constructor=g,ei(p)){x.s=p.s,S?!p.d||p.e>g.maxE?(x.e=NaN,x.d=null):p.e=10;T/=10)E++;S?E>g.maxE?(x.e=NaN,x.d=null):E=429e7?u[p]=crypto.getRandomValues(new Uint32Array(1))[0]:T[p++]=g%1e7;else if(crypto.randomBytes){for(u=crypto.randomBytes(f*=4);p=214e7?crypto.randomBytes(4).copy(u,p):(T.push(g%1e7),p+=4);p=f/4}else throw Error(se);else for(;p=10;g/=10)f++;f{(function(){var s,r="4.17.21",l=200,c="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",d="Expected a function",C="Invalid `variable` option passed into `_.template`",_="__lodash_hash_undefined__",m=500,A="__lodash_placeholder__",P=1,y=2,S=4,V=1,M=2,Y=1,se=2,ge=4,D=8,$=16,U=32,K=64,te=128,J=256,Q=512,G=30,Ce="...",Pe=800,ot=16,B=1,Oe=2,je=3,vt=1/0,_t=9007199254740991,Lo=17976931348623157e292,Ae=NaN,j=4294967295,Mt=j-1,gr=j>>>1,pr=[["ary",te],["bind",Y],["bindKey",se],["curry",D],["curryRight",$],["flip",Q],["partial",U],["partialRight",K],["rearg",J]],Ze="[object Arguments]",zn="[object Array]",tn="[object AsyncFunction]",En="[object Boolean]",An="[object Date]",Di="[object DOMException]",Tn="[object Error]",bt="[object Function]",Zr="[object GeneratorFunction]",st="[object Map]",$n="[object Number]",Oo="[object Null]",et="[object Object]",Zn="[object Promise]",Fi="[object Proxy]",cn="[object RegExp]",ht="[object Set]",Gn="[object String]",mr="[object Symbol]",So="[object Undefined]",Vn="[object WeakMap]",Po="[object WeakSet]",Kn="[object ArrayBuffer]",Rn="[object DataView]",Gr="[object Float32Array]",Vr="[object Float64Array]",Kr="[object Int8Array]",Yr="[object Int16Array]",Jr="[object Int32Array]",Xr="[object Uint8Array]",Qr="[object Uint8ClampedArray]",jr="[object Uint16Array]",wr="[object Uint32Array]",Io=/\b__p \+= '';/g,Wo=/\b(__p \+=) '' \+/g,Mo=/(__e\(.*?\)|\b__t\)) \+\n'';/g,ki=/&(?:amp|lt|gt|quot|#39);/g,ei=/[&<>"']/g,Do=RegExp(ki.source),Fo=RegExp(ei.source),ko=/<%-([\s\S]+?)%>/g,Uo=/<%([\s\S]+?)%>/g,Ui=/<%=([\s\S]+?)%>/g,qo=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Ho=/^\w*$/,Bo=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,ti=/[\\^$.*+?()[\]{}|]/g,zo=RegExp(ti.source),ni=/^\s+/,$o=/\s/,Zo=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Go=/\{\n\/\* \[wrapped with (.+)\] \*/,Vo=/,? & /,Ko=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,Yo=/[()=,{}\[\]\/\s]/,Jo=/\\(\\)?/g,Xo=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,qi=/\w*$/,o=/^[-+]0x[0-9a-f]+$/i,u=/^0b[01]+$/i,a=/^\[object .+?Constructor\]$/,f=/^0o[0-7]+$/i,g=/^(?:0|[1-9]\d*)$/,p=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,E=/($^)/,T=/['\n\r\u2028\u2029\\]/g,L="\\ud800-\\udfff",x="\\u0300-\\u036f",I="\\ufe20-\\ufe2f",F="\\u20d0-\\u20ff",z=x+I+F,ie="\\u2700-\\u27bf",_e="a-z\\xdf-\\xf6\\xf8-\\xff",ce="\\xac\\xb1\\xd7\\xf7",Ye="\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf",Me="\\u2000-\\u206f",Et=" \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Re="A-Z\\xc0-\\xd6\\xd8-\\xde",Be="\\ufe0e\\ufe0f",Yn=ce+Ye+Me+Et,At="['\u2019]",ri="["+L+"]",Jn="["+Yn+"]",nn="["+z+"]",Cr="\\d+",Tt="["+ie+"]",Xn="["+_e+"]",Qn="[^"+L+Yn+Cr+ie+_e+Re+"]",jn="\\ud83c[\\udffb-\\udfff]",Ge="(?:"+nn+"|"+jn+")",ye="[^"+L+"]",Qo="(?:\\ud83c[\\udde6-\\uddff]){2}",jo="[\\ud800-\\udbff][\\udc00-\\udfff]",vr="["+Re+"]",r0="\\u200d",i0="(?:"+Xn+"|"+Qn+")",du="(?:"+vr+"|"+Qn+")",o0="(?:"+At+"(?:d|ll|m|re|s|t|ve))?",s0="(?:"+At+"(?:D|LL|M|RE|S|T|VE))?",l0=Ge+"?",u0="["+Be+"]?",gu="(?:"+r0+"(?:"+[ye,Qo,jo].join("|")+")"+u0+l0+")*",pu="\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",mu="\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])",a0=u0+l0+gu,wu="(?:"+[Tt,Qo,jo].join("|")+")"+a0,Cu="(?:"+[ye+nn+"?",nn,Qo,jo,ri].join("|")+")",vu=RegExp(At,"g"),_u=RegExp(nn,"g"),e2=RegExp(jn+"(?="+jn+")|"+Cu+a0,"g"),bu=RegExp([vr+"?"+Xn+"+"+o0+"(?="+[Jn,vr,"$"].join("|")+")",du+"+"+s0+"(?="+[Jn,vr+i0,"$"].join("|")+")",vr+"?"+i0+"+"+o0,vr+"+"+s0,mu,pu,Cr,wu].join("|"),"g"),Eu=RegExp("["+r0+L+z+Be+"]"),Au=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Tu=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Ru=-1,De={};De[Gr]=De[Vr]=De[Kr]=De[Yr]=De[Jr]=De[Xr]=De[Qr]=De[jr]=De[wr]=!0,De[Ze]=De[zn]=De[Kn]=De[En]=De[Rn]=De[An]=De[Tn]=De[bt]=De[st]=De[$n]=De[et]=De[cn]=De[ht]=De[Gn]=De[Vn]=!1;var Ie={};Ie[Ze]=Ie[zn]=Ie[Kn]=Ie[Rn]=Ie[En]=Ie[An]=Ie[Gr]=Ie[Vr]=Ie[Kr]=Ie[Yr]=Ie[Jr]=Ie[st]=Ie[$n]=Ie[et]=Ie[cn]=Ie[ht]=Ie[Gn]=Ie[mr]=Ie[Xr]=Ie[Qr]=Ie[jr]=Ie[wr]=!0,Ie[Tn]=Ie[bt]=Ie[Vn]=!1;var xu={\u00C0:"A",\u00C1:"A",\u00C2:"A",\u00C3:"A",\u00C4:"A",\u00C5:"A",\u00E0:"a",\u00E1:"a",\u00E2:"a",\u00E3:"a",\u00E4:"a",\u00E5:"a",\u00C7:"C",\u00E7:"c",\u00D0:"D",\u00F0:"d",\u00C8:"E",\u00C9:"E",\u00CA:"E",\u00CB:"E",\u00E8:"e",\u00E9:"e",\u00EA:"e",\u00EB:"e",\u00CC:"I",\u00CD:"I",\u00CE:"I",\u00CF:"I",\u00EC:"i",\u00ED:"i",\u00EE:"i",\u00EF:"i",\u00D1:"N",\u00F1:"n",\u00D2:"O",\u00D3:"O",\u00D4:"O",\u00D5:"O",\u00D6:"O",\u00D8:"O",\u00F2:"o",\u00F3:"o",\u00F4:"o",\u00F5:"o",\u00F6:"o",\u00F8:"o",\u00D9:"U",\u00DA:"U",\u00DB:"U",\u00DC:"U",\u00F9:"u",\u00FA:"u",\u00FB:"u",\u00FC:"u",\u00DD:"Y",\u00FD:"y",\u00FF:"y",\u00C6:"Ae",\u00E6:"ae",\u00DE:"Th",\u00FE:"th",\u00DF:"ss",\u0100:"A",\u0102:"A",\u0104:"A",\u0101:"a",\u0103:"a",\u0105:"a",\u0106:"C",\u0108:"C",\u010A:"C",\u010C:"C",\u0107:"c",\u0109:"c",\u010B:"c",\u010D:"c",\u010E:"D",\u0110:"D",\u010F:"d",\u0111:"d",\u0112:"E",\u0114:"E",\u0116:"E",\u0118:"E",\u011A:"E",\u0113:"e",\u0115:"e",\u0117:"e",\u0119:"e",\u011B:"e",\u011C:"G",\u011E:"G",\u0120:"G",\u0122:"G",\u011D:"g",\u011F:"g",\u0121:"g",\u0123:"g",\u0124:"H",\u0126:"H",\u0125:"h",\u0127:"h",\u0128:"I",\u012A:"I",\u012C:"I",\u012E:"I",\u0130:"I",\u0129:"i",\u012B:"i",\u012D:"i",\u012F:"i",\u0131:"i",\u0134:"J",\u0135:"j",\u0136:"K",\u0137:"k",\u0138:"k",\u0139:"L",\u013B:"L",\u013D:"L",\u013F:"L",\u0141:"L",\u013A:"l",\u013C:"l",\u013E:"l",\u0140:"l",\u0142:"l",\u0143:"N",\u0145:"N",\u0147:"N",\u014A:"N",\u0144:"n",\u0146:"n",\u0148:"n",\u014B:"n",\u014C:"O",\u014E:"O",\u0150:"O",\u014D:"o",\u014F:"o",\u0151:"o",\u0154:"R",\u0156:"R",\u0158:"R",\u0155:"r",\u0157:"r",\u0159:"r",\u015A:"S",\u015C:"S",\u015E:"S",\u0160:"S",\u015B:"s",\u015D:"s",\u015F:"s",\u0161:"s",\u0162:"T",\u0164:"T",\u0166:"T",\u0163:"t",\u0165:"t",\u0167:"t",\u0168:"U",\u016A:"U",\u016C:"U",\u016E:"U",\u0170:"U",\u0172:"U",\u0169:"u",\u016B:"u",\u016D:"u",\u016F:"u",\u0171:"u",\u0173:"u",\u0174:"W",\u0175:"w",\u0176:"Y",\u0177:"y",\u0178:"Y",\u0179:"Z",\u017B:"Z",\u017D:"Z",\u017A:"z",\u017C:"z",\u017E:"z",\u0132:"IJ",\u0133:"ij",\u0152:"Oe",\u0153:"oe",\u0149:"'n",\u017F:"s"},yu={"&":"&","<":"<",">":">",'"':""","'":"'"},Nu={"&":"&","<":"<",">":">",""":'"',"'":"'"},Lu={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Ou=parseFloat,Su=parseInt,c0=typeof global=="object"&&global&&global.Object===Object&&global,Pu=typeof self=="object"&&self&&self.Object===Object&&self,Ve=c0||Pu||Function("return this")(),t2=typeof Ir=="object"&&Ir&&!Ir.nodeType&&Ir,er=t2&&typeof bi=="object"&&bi&&!bi.nodeType&&bi,f0=er&&er.exports===t2,n2=f0&&c0.process,Dt=function(){try{var N=er&&er.require&&er.require("util").types;return N||n2&&n2.binding&&n2.binding("util")}catch(k){}}(),h0=Dt&&Dt.isArrayBuffer,d0=Dt&&Dt.isDate,g0=Dt&&Dt.isMap,p0=Dt&&Dt.isRegExp,m0=Dt&&Dt.isSet,w0=Dt&&Dt.isTypedArray;function Rt(N,k,W){switch(W.length){case 0:return N.call(k);case 1:return N.call(k,W[0]);case 2:return N.call(k,W[0],W[1]);case 3:return N.call(k,W[0],W[1],W[2])}return N.apply(k,W)}function Iu(N,k,W,ee){for(var fe=-1,Te=N==null?0:N.length;++fe-1}function r2(N,k,W){for(var ee=-1,fe=N==null?0:N.length;++ee-1;);return W}function R0(N,k){for(var W=N.length;W--&&_r(k,N[W],0)>-1;);return W}function Bu(N,k){for(var W=N.length,ee=0;W--;)N[W]===k&&++ee;return ee}var zu=l2(xu),$u=l2(yu);function Zu(N){return"\\"+Lu[N]}function Gu(N,k){return N==null?s:N[k]}function br(N){return Eu.test(N)}function Vu(N){return Au.test(N)}function Ku(N){for(var k,W=[];!(k=N.next()).done;)W.push(k.value);return W}function f2(N){var k=-1,W=Array(N.size);return N.forEach(function(ee,fe){W[++k]=[fe,ee]}),W}function x0(N,k){return function(W){return N(k(W))}}function Nn(N,k){for(var W=-1,ee=N.length,fe=0,Te=[];++W-1}function M4(e,t){var n=this.__data__,i=i1(n,e);return i<0?(++this.size,n.push([e,t])):n[i][1]=t,this}fn.prototype.clear=S4,fn.prototype.delete=P4,fn.prototype.get=I4,fn.prototype.has=W4,fn.prototype.set=M4;function hn(e){var t=-1,n=e==null?0:e.length;for(this.clear();++t=t?e:t)),e}function qt(e,t,n,i,h,v){var b,R=t&P,O=t&y,q=t&S;if(n&&(b=h?n(e,i,h,v):n(e)),b!==s)return b;if(!ke(e))return e;var H=he(e);if(H){if(b=U6(e),!R)return dt(e,b)}else{var Z=nt(e),X=Z==bt||Z==Zr;if(Mn(e))return us(e,R);if(Z==et||Z==Ze||X&&!h){if(b=O||X?{}:ys(e),!R)return O?N6(e,X4(b,e)):y6(e,k0(b,e))}else{if(!Ie[Z])return h?e:{};b=q6(e,Z,R)}}v||(v=new Kt);var ne=v.get(e);if(ne)return ne;v.set(e,b),nl(e)?e.forEach(function(ae){b.add(qt(ae,t,n,ae,e,v))}):el(e)&&e.forEach(function(ae,ve){b.set(ve,qt(ae,t,n,ve,e,v))});var ue=q?O?F2:D2:O?pt:Ke,pe=H?s:ue(e);return Ft(pe||e,function(ae,ve){pe&&(ve=ae,ae=e[ve]),ci(b,ve,qt(ae,t,n,ve,e,v))}),b}function Q4(e){var t=Ke(e);return function(n){return U0(n,e,t)}}function U0(e,t,n){var i=n.length;if(e==null)return!i;for(e=Se(e);i--;){var h=n[i],v=t[h],b=e[h];if(b===s&&!(h in e)||!v(b))return!1}return!0}function q0(e,t,n){if(typeof e!="function")throw new kt(d);return wi(function(){e.apply(s,n)},t)}function fi(e,t,n,i){var h=-1,v=Hi,b=!0,R=e.length,O=[],q=t.length;if(!R)return O;n&&(t=Fe(t,xt(n))),i?(v=r2,b=!1):t.length>=l&&(v=ii,b=!1,t=new rr(t));e:for(;++hh?0:h+n),i=i===s||i>h?h:de(i),i<0&&(i+=h),i=n>i?0:il(i);n0&&n(R)?t>1?Je(R,t-1,n,i,h):yn(h,R):i||(h[h.length]=R)}return h}var C2=gs(),z0=gs(!0);function rn(e,t){return e&&C2(e,t,Ke)}function v2(e,t){return e&&z0(e,t,Ke)}function s1(e,t){return xn(t,function(n){return wn(e[n])})}function or(e,t){t=In(t,e);for(var n=0,i=t.length;e!=null&&nt}function t6(e,t){return e!=null&&Ne.call(e,t)}function n6(e,t){return e!=null&&t in Se(e)}function r6(e,t,n){return e>=tt(t,n)&&e<$e(t,n)}function b2(e,t,n){for(var i=n?r2:Hi,h=e[0].length,v=e.length,b=v,R=W(v),O=1/0,q=[];b--;){var H=e[b];b&&t&&(H=Fe(H,xt(t))),O=tt(H.length,O),R[b]=!n&&(t||h>=120&&H.length>=120)?new rr(b&&H):s}H=e[0];var Z=-1,X=R[0];e:for(;++Z-1;)R!==e&&Xi.call(R,O,1),Xi.call(e,O,1);return e}function es(e,t){for(var n=e?t.length:0,i=n-1;n--;){var h=t[n];if(n==i||h!==v){var v=h;mn(h)?Xi.call(e,h,1):L2(e,h)}}return e}function x2(e,t){return e+e1(W0()*(t-e+1))}function m6(e,t,n,i){for(var h=-1,v=$e(ji((t-e)/(n||1)),0),b=W(v);v--;)b[i?v:++h]=e,e+=n;return b}function y2(e,t){var n="";if(!e||t<1||t>_t)return n;do t%2&&(n+=e),t=e1(t/2),t&&(e+=e);while(t);return n}function me(e,t){return $2(Os(e,t,mt),e+"")}function w6(e){return F0(Sr(e))}function C6(e,t){var n=Sr(e);return w1(n,ir(t,0,n.length))}function gi(e,t,n,i){if(!ke(e))return e;t=In(t,e);for(var h=-1,v=t.length,b=v-1,R=e;R!=null&&++hh?0:h+t),n=n>h?h:n,n<0&&(n+=h),h=t>n?0:n-t>>>0,t>>>=0;for(var v=W(h);++i>>1,b=e[v];b!==null&&!Nt(b)&&(n?b<=t:b=l){var q=t?null:P6(e);if(q)return zi(q);b=!1,h=ii,O=new rr}else O=t?[]:R;e:for(;++i=i?e:Ht(e,t,n)}var ls=a4||function(e){return Ve.clearTimeout(e)};function us(e,t){if(t)return e.slice();var n=e.length,i=L0?L0(n):new e.constructor(n);return e.copy(i),i}function I2(e){var t=new e.constructor(e.byteLength);return new Yi(t).set(new Yi(e)),t}function A6(e,t){var n=t?I2(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}function T6(e){var t=new e.constructor(e.source,qi.exec(e));return t.lastIndex=e.lastIndex,t}function R6(e){return ai?Se(ai.call(e)):{}}function as(e,t){var n=t?I2(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function cs(e,t){if(e!==t){var n=e!==s,i=e===null,h=e===e,v=Nt(e),b=t!==s,R=t===null,O=t===t,q=Nt(t);if(!R&&!q&&!v&&e>t||v&&b&&O&&!R&&!q||i&&b&&O||!n&&O||!h)return 1;if(!i&&!v&&!q&&e=R)return O;var q=n[i];return O*(q=="desc"?-1:1)}}return e.index-t.index}function fs(e,t,n,i){for(var h=-1,v=e.length,b=n.length,R=-1,O=t.length,q=$e(v-b,0),H=W(O+q),Z=!i;++R1?n[h-1]:s,b=h>2?n[2]:s;for(v=e.length>3&&typeof v=="function"?(h--,v):s,b&&ut(n[0],n[1],b)&&(v=h<3?s:v,h=1),t=Se(t);++i-1?h[v?t[b]:b]:s}}function ws(e){return pn(function(t){var n=t.length,i=n,h=Ut.prototype.thru;for(e&&t.reverse();i--;){var v=t[i];if(typeof v!="function")throw new kt(d);if(h&&!b&&p1(v)=="wrapper")var b=new Ut([],!0)}for(i=b?i:n;++i1&&Ee.reverse(),H&&OR))return!1;var q=v.get(e),H=v.get(t);if(q&&H)return q==t&&H==e;var Z=-1,X=!0,ne=n&M?new rr:s;for(v.set(e,t),v.set(t,e);++Z1?"& ":"")+t[i],t=t.join(n>2?", ":" "),e.replace(Zo,`{ +/* [wrapped with `+t+`] */ +`)}function B6(e){return he(e)||ur(e)||!!(P0&&e&&e[P0])}function mn(e,t){var n=typeof e;return t=t==null?_t:t,!!t&&(n=="number"||n!="symbol"&&g.test(e))&&e>-1&&e%1==0&&e0){if(++t>=Pe)return arguments[0]}else t=0;return e.apply(s,arguments)}}function w1(e,t){var n=-1,i=e.length,h=i-1;for(t=t===s?i:t;++n1?e[t-1]:s;return n=typeof n=="function"?(e.pop(),n):s,Bs(e,n)});function zs(e){var t=w(e);return t.__chain__=!0,t}function ja(e,t){return t(e),e}function C1(e,t){return t(e)}var e8=pn(function(e){var t=e.length,n=t?e[0]:0,i=this.__wrapped__,h=function(v){return w2(v,e)};return t>1||this.__actions__.length||!(i instanceof be)||!mn(n)?this.thru(h):(i=i.slice(n,+n+(t?1:0)),i.__actions__.push({func:C1,args:[h],thisArg:s}),new Ut(i,this.__chain__).thru(function(v){return t&&!v.length&&v.push(s),v}))});function t8(){return zs(this)}function n8(){return new Ut(this.value(),this.__chain__)}function r8(){this.__values__===s&&(this.__values__=rl(this.value()));var e=this.__index__>=this.__values__.length,t=e?s:this.__values__[this.__index__++];return{done:e,value:t}}function i8(){return this}function o8(e){for(var t,n=this;n instanceof r1;){var i=Ds(n);i.__index__=0,i.__values__=s,t?h.__wrapped__=i:t=i;var h=i;n=n.__wrapped__}return h.__wrapped__=e,t}function s8(){var e=this.__wrapped__;if(e instanceof be){var t=e;return this.__actions__.length&&(t=new be(this)),t=t.reverse(),t.__actions__.push({func:C1,args:[Z2],thisArg:s}),new Ut(t,this.__chain__)}return this.thru(Z2)}function l8(){return os(this.__wrapped__,this.__actions__)}var u8=c1(function(e,t,n){Ne.call(e,n)?++e[n]:dn(e,n,1)});function a8(e,t,n){var i=he(e)?C0:j4;return n&&ut(e,t,n)&&(t=s),i(e,le(t,3))}function c8(e,t){var n=he(e)?xn:B0;return n(e,le(t,3))}var f8=ms(Fs),h8=ms(ks);function d8(e,t){return Je(v1(e,t),1)}function g8(e,t){return Je(v1(e,t),vt)}function p8(e,t,n){return n=n===s?1:de(n),Je(v1(e,t),n)}function $s(e,t){var n=he(e)?Ft:Sn;return n(e,le(t,3))}function Zs(e,t){var n=he(e)?Wu:H0;return n(e,le(t,3))}var m8=c1(function(e,t,n){Ne.call(e,n)?e[n].push(t):dn(e,n,[t])});function w8(e,t,n,i){e=gt(e)?e:Sr(e),n=n&&!i?de(n):0;var h=e.length;return n<0&&(n=$e(h+n,0)),T1(e)?n<=h&&e.indexOf(t,n)>-1:!!h&&_r(e,t,n)>-1}var C8=me(function(e,t,n){var i=-1,h=typeof t=="function",v=gt(e)?W(e.length):[];return Sn(e,function(b){v[++i]=h?Rt(t,b,n):hi(b,t,n)}),v}),v8=c1(function(e,t,n){dn(e,n,t)});function v1(e,t){var n=he(e)?Fe:K0;return n(e,le(t,3))}function _8(e,t,n,i){return e==null?[]:(he(t)||(t=t==null?[]:[t]),n=i?s:n,he(n)||(n=n==null?[]:[n]),Q0(e,t,n))}var b8=c1(function(e,t,n){e[n?0:1].push(t)},function(){return[[],[]]});function E8(e,t,n){var i=he(e)?i2:E0,h=arguments.length<3;return i(e,le(t,4),n,h,Sn)}function A8(e,t,n){var i=he(e)?Mu:E0,h=arguments.length<3;return i(e,le(t,4),n,h,H0)}function T8(e,t){var n=he(e)?xn:B0;return n(e,E1(le(t,3)))}function R8(e){var t=he(e)?F0:w6;return t(e)}function x8(e,t,n){(n?ut(e,t,n):t===s)?t=1:t=de(t);var i=he(e)?K4:C6;return i(e,t)}function y8(e){var t=he(e)?Y4:_6;return t(e)}function N8(e){if(e==null)return 0;if(gt(e))return T1(e)?Er(e):e.length;var t=nt(e);return t==st||t==ht?e.size:A2(e).length}function L8(e,t,n){var i=he(e)?o2:b6;return n&&ut(e,t,n)&&(t=s),i(e,le(t,3))}var O8=me(function(e,t){if(e==null)return[];var n=t.length;return n>1&&ut(e,t[0],t[1])?t=[]:n>2&&ut(t[0],t[1],t[2])&&(t=[t[0]]),Q0(e,Je(t,1),[])}),_1=c4||function(){return Ve.Date.now()};function S8(e,t){if(typeof t!="function")throw new kt(d);return e=de(e),function(){if(--e<1)return t.apply(this,arguments)}}function Gs(e,t,n){return t=n?s:t,t=e&&t==null?e.length:t,gn(e,te,s,s,s,s,t)}function Vs(e,t){var n;if(typeof t!="function")throw new kt(d);return e=de(e),function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=s),n}}var V2=me(function(e,t,n){var i=Y;if(n.length){var h=Nn(n,Lr(V2));i|=U}return gn(e,i,t,n,h)}),Ks=me(function(e,t,n){var i=Y|se;if(n.length){var h=Nn(n,Lr(Ks));i|=U}return gn(t,i,e,n,h)});function Ys(e,t,n){t=n?s:t;var i=gn(e,D,s,s,s,s,s,t);return i.placeholder=Ys.placeholder,i}function Js(e,t,n){t=n?s:t;var i=gn(e,$,s,s,s,s,s,t);return i.placeholder=Js.placeholder,i}function Xs(e,t,n){var i,h,v,b,R,O,q=0,H=!1,Z=!1,X=!0;if(typeof e!="function")throw new kt(d);t=zt(t)||0,ke(n)&&(H=!!n.leading,Z="maxWait"in n,v=Z?$e(zt(n.maxWait)||0,t):v,X="trailing"in n?!!n.trailing:X);function ne(He){var Jt=i,vn=h;return i=h=s,q=He,b=e.apply(vn,Jt),b}function ue(He){return q=He,R=wi(ve,t),H?ne(He):b}function pe(He){var Jt=He-O,vn=He-q,ml=t-Jt;return Z?tt(ml,v-vn):ml}function ae(He){var Jt=He-O,vn=He-q;return O===s||Jt>=t||Jt<0||Z&&vn>=v}function ve(){var He=_1();if(ae(He))return Ee(He);R=wi(ve,pe(He))}function Ee(He){return R=s,X&&i?ne(He):(i=h=s,b)}function Lt(){R!==s&&ls(R),q=0,i=O=h=R=s}function at(){return R===s?b:Ee(_1())}function Ot(){var He=_1(),Jt=ae(He);if(i=arguments,h=this,O=He,Jt){if(R===s)return ue(O);if(Z)return ls(R),R=wi(ve,t),ne(O)}return R===s&&(R=wi(ve,t)),b}return Ot.cancel=Lt,Ot.flush=at,Ot}var P8=me(function(e,t){return q0(e,1,t)}),I8=me(function(e,t,n){return q0(e,zt(t)||0,n)});function W8(e){return gn(e,Q)}function b1(e,t){if(typeof e!="function"||t!=null&&typeof t!="function")throw new kt(d);var n=function(){var i=arguments,h=t?t.apply(this,i):i[0],v=n.cache;if(v.has(h))return v.get(h);var b=e.apply(this,i);return n.cache=v.set(h,b)||v,b};return n.cache=new(b1.Cache||hn),n}b1.Cache=hn;function E1(e){if(typeof e!="function")throw new kt(d);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}function M8(e){return Vs(2,e)}var D8=E6(function(e,t){t=t.length==1&&he(t[0])?Fe(t[0],xt(le())):Fe(Je(t,1),xt(le()));var n=t.length;return me(function(i){for(var h=-1,v=tt(i.length,n);++h=t}),ur=Z0(function(){return arguments}())?Z0:function(e){return Ue(e)&&Ne.call(e,"callee")&&!S0.call(e,"callee")},he=W.isArray,X8=h0?xt(h0):o6;function gt(e){return e!=null&&A1(e.length)&&!wn(e)}function qe(e){return Ue(e)&>(e)}function Q8(e){return e===!0||e===!1||Ue(e)&<(e)==En}var Mn=h4||o3,j8=d0?xt(d0):s6;function e5(e){return Ue(e)&&e.nodeType===1&&!Ci(e)}function t5(e){if(e==null)return!0;if(gt(e)&&(he(e)||typeof e=="string"||typeof e.splice=="function"||Mn(e)||Or(e)||ur(e)))return!e.length;var t=nt(e);if(t==st||t==ht)return!e.size;if(mi(e))return!A2(e).length;for(var n in e)if(Ne.call(e,n))return!1;return!0}function n5(e,t){return di(e,t)}function r5(e,t,n){n=typeof n=="function"?n:s;var i=n?n(e,t):s;return i===s?di(e,t,s,n):!!i}function Y2(e){if(!Ue(e))return!1;var t=lt(e);return t==Tn||t==Di||typeof e.message=="string"&&typeof e.name=="string"&&!Ci(e)}function i5(e){return typeof e=="number"&&I0(e)}function wn(e){if(!ke(e))return!1;var t=lt(e);return t==bt||t==Zr||t==tn||t==Fi}function js(e){return typeof e=="number"&&e==de(e)}function A1(e){return typeof e=="number"&&e>-1&&e%1==0&&e<=_t}function ke(e){var t=typeof e;return e!=null&&(t=="object"||t=="function")}function Ue(e){return e!=null&&typeof e=="object"}var el=g0?xt(g0):u6;function o5(e,t){return e===t||E2(e,t,U2(t))}function s5(e,t,n){return n=typeof n=="function"?n:s,E2(e,t,U2(t),n)}function l5(e){return tl(e)&&e!=+e}function u5(e){if(Z6(e))throw new fe(c);return G0(e)}function a5(e){return e===null}function c5(e){return e==null}function tl(e){return typeof e=="number"||Ue(e)&<(e)==$n}function Ci(e){if(!Ue(e)||lt(e)!=et)return!1;var t=Ji(e);if(t===null)return!0;var n=Ne.call(t,"constructor")&&t.constructor;return typeof n=="function"&&n instanceof n&&Gi.call(n)==s4}var J2=p0?xt(p0):a6;function f5(e){return js(e)&&e>=-_t&&e<=_t}var nl=m0?xt(m0):c6;function T1(e){return typeof e=="string"||!he(e)&&Ue(e)&<(e)==Gn}function Nt(e){return typeof e=="symbol"||Ue(e)&<(e)==mr}var Or=w0?xt(w0):f6;function h5(e){return e===s}function d5(e){return Ue(e)&&nt(e)==Vn}function g5(e){return Ue(e)&<(e)==Po}var p5=g1(T2),m5=g1(function(e,t){return e<=t});function rl(e){if(!e)return[];if(gt(e))return T1(e)?Vt(e):dt(e);if(oi&&e[oi])return Ku(e[oi]());var t=nt(e),n=t==st?f2:t==ht?zi:Sr;return n(e)}function Cn(e){if(!e)return e===0?e:0;if(e=zt(e),e===vt||e===-vt){var t=e<0?-1:1;return t*Lo}return e===e?e:0}function de(e){var t=Cn(e),n=t%1;return t===t?n?t-n:t:0}function il(e){return e?ir(de(e),0,j):0}function zt(e){if(typeof e=="number")return e;if(Nt(e))return Ae;if(ke(e)){var t=typeof e.valueOf=="function"?e.valueOf():e;e=ke(t)?t+"":t}if(typeof e!="string")return e===0?e:+e;e=A0(e);var n=u.test(e);return n||f.test(e)?Su(e.slice(2),n?2:8):o.test(e)?Ae:+e}function ol(e){return on(e,pt(e))}function w5(e){return e?ir(de(e),-_t,_t):e===0?e:0}function xe(e){return e==null?"":yt(e)}var C5=yr(function(e,t){if(mi(t)||gt(t)){on(t,Ke(t),e);return}for(var n in t)Ne.call(t,n)&&ci(e,n,t[n])}),sl=yr(function(e,t){on(t,pt(t),e)}),R1=yr(function(e,t,n,i){on(t,pt(t),e,i)}),v5=yr(function(e,t,n,i){on(t,Ke(t),e,i)}),_5=pn(w2);function b5(e,t){var n=xr(e);return t==null?n:k0(n,t)}var E5=me(function(e,t){e=Se(e);var n=-1,i=t.length,h=i>2?t[2]:s;for(h&&ut(t[0],t[1],h)&&(i=1);++n1),v}),on(e,F2(e),n),i&&(n=qt(n,P|y|S,I6));for(var h=t.length;h--;)L2(n,t[h]);return n});function q5(e,t){return ul(e,E1(le(t)))}var H5=pn(function(e,t){return e==null?{}:g6(e,t)});function ul(e,t){if(e==null)return{};var n=Fe(F2(e),function(i){return[i]});return t=le(t),j0(e,n,function(i,h){return t(i,h[0])})}function B5(e,t,n){t=In(t,e);var i=-1,h=t.length;for(h||(h=1,e=s);++it){var i=e;e=t,t=i}if(n||e%1||t%1){var h=W0();return tt(e+h*(t-e+Ou("1e-"+((h+"").length-1))),t)}return x2(e,t)}var j5=Nr(function(e,t,n){return t=t.toLowerCase(),e+(n?fl(t):t)});function fl(e){return j2(xe(e).toLowerCase())}function hl(e){return e=xe(e),e&&e.replace(p,zu).replace(_u,"")}function ec(e,t,n){e=xe(e),t=yt(t);var i=e.length;n=n===s?i:ir(de(n),0,i);var h=n;return n-=t.length,n>=0&&e.slice(n,h)==t}function tc(e){return e=xe(e),e&&Fo.test(e)?e.replace(ei,$u):e}function nc(e){return e=xe(e),e&&zo.test(e)?e.replace(ti,"\\$&"):e}var rc=Nr(function(e,t,n){return e+(n?"-":"")+t.toLowerCase()}),ic=Nr(function(e,t,n){return e+(n?" ":"")+t.toLowerCase()}),oc=ps("toLowerCase");function sc(e,t,n){e=xe(e),t=de(t);var i=t?Er(e):0;if(!t||i>=t)return e;var h=(t-i)/2;return d1(e1(h),n)+e+d1(ji(h),n)}function lc(e,t,n){e=xe(e),t=de(t);var i=t?Er(e):0;return t&&i>>0,n?(e=xe(e),e&&(typeof t=="string"||t!=null&&!J2(t))&&(t=yt(t),!t&&br(e))?Wn(Vt(e),0,n):e.split(t,n)):[]}var gc=Nr(function(e,t,n){return e+(n?" ":"")+j2(t)});function pc(e,t,n){return e=xe(e),n=n==null?0:ir(de(n),0,e.length),t=yt(t),e.slice(n,n+t.length)==t}function mc(e,t,n){var i=w.templateSettings;n&&ut(e,t,n)&&(t=s),e=xe(e),t=R1({},t,i,Es);var h=R1({},t.imports,i.imports,Es),v=Ke(h),b=c2(h,v),R,O,q=0,H=t.interpolate||E,Z="__p += '",X=h2((t.escape||E).source+"|"+H.source+"|"+(H===Ui?Xo:E).source+"|"+(t.evaluate||E).source+"|$","g"),ne="//# sourceURL="+(Ne.call(t,"sourceURL")?(t.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++Ru+"]")+` +`;e.replace(X,function(ae,ve,Ee,Lt,at,Ot){return Ee||(Ee=Lt),Z+=e.slice(q,Ot).replace(T,Zu),ve&&(R=!0,Z+=`' + +__e(`+ve+`) + +'`),at&&(O=!0,Z+=`'; +`+at+`; +__p += '`),Ee&&(Z+=`' + +((__t = (`+Ee+`)) == null ? '' : __t) + +'`),q=Ot+ae.length,ae}),Z+=`'; +`;var ue=Ne.call(t,"variable")&&t.variable;if(!ue)Z=`with (obj) { +`+Z+` +} +`;else if(Yo.test(ue))throw new fe(C);Z=(O?Z.replace(Io,""):Z).replace(Wo,"$1").replace(Mo,"$1;"),Z="function("+(ue||"obj")+`) { +`+(ue?"":`obj || (obj = {}); +`)+"var __t, __p = ''"+(R?", __e = _.escape":"")+(O?`, __j = Array.prototype.join; +function print() { __p += __j.call(arguments, '') } +`:`; +`)+Z+`return __p +}`;var pe=gl(function(){return Te(v,ne+"return "+Z).apply(s,b)});if(pe.source=Z,Y2(pe))throw pe;return pe}function wc(e){return xe(e).toLowerCase()}function Cc(e){return xe(e).toUpperCase()}function vc(e,t,n){if(e=xe(e),e&&(n||t===s))return A0(e);if(!e||!(t=yt(t)))return e;var i=Vt(e),h=Vt(t),v=T0(i,h),b=R0(i,h)+1;return Wn(i,v,b).join("")}function _c(e,t,n){if(e=xe(e),e&&(n||t===s))return e.slice(0,y0(e)+1);if(!e||!(t=yt(t)))return e;var i=Vt(e),h=R0(i,Vt(t))+1;return Wn(i,0,h).join("")}function bc(e,t,n){if(e=xe(e),e&&(n||t===s))return e.replace(ni,"");if(!e||!(t=yt(t)))return e;var i=Vt(e),h=T0(i,Vt(t));return Wn(i,h).join("")}function Ec(e,t){var n=G,i=Ce;if(ke(t)){var h="separator"in t?t.separator:h;n="length"in t?de(t.length):n,i="omission"in t?yt(t.omission):i}e=xe(e);var v=e.length;if(br(e)){var b=Vt(e);v=b.length}if(n>=v)return e;var R=n-Er(i);if(R<1)return i;var O=b?Wn(b,0,R).join(""):e.slice(0,R);if(h===s)return O+i;if(b&&(R+=O.length-R),J2(h)){if(e.slice(R).search(h)){var q,H=O;for(h.global||(h=h2(h.source,xe(qi.exec(h))+"g")),h.lastIndex=0;q=h.exec(H);)var Z=q.index;O=O.slice(0,Z===s?R:Z)}}else if(e.indexOf(yt(h),R)!=R){var X=O.lastIndexOf(h);X>-1&&(O=O.slice(0,X))}return O+i}function Ac(e){return e=xe(e),e&&Do.test(e)?e.replace(ki,Qu):e}var Tc=Nr(function(e,t,n){return e+(n?" ":"")+t.toUpperCase()}),j2=ps("toUpperCase");function dl(e,t,n){return e=xe(e),t=n?s:t,t===s?Vu(e)?t4(e):ku(e):e.match(t)||[]}var gl=me(function(e,t){try{return Rt(e,s,t)}catch(n){return Y2(n)?n:new fe(n)}}),Rc=pn(function(e,t){return Ft(t,function(n){n=sn(n),dn(e,n,V2(e[n],e))}),e});function xc(e){var t=e==null?0:e.length,n=le();return e=t?Fe(e,function(i){if(typeof i[1]!="function")throw new kt(d);return[n(i[0]),i[1]]}):[],me(function(i){for(var h=-1;++h_t)return[];var n=j,i=tt(e,j);t=le(t),e-=j;for(var h=a2(i,t);++n0||t<0)?new be(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),t!==s&&(t=de(t),n=t<0?n.dropRight(-t):n.take(t-e)),n)},be.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},be.prototype.toArray=function(){return this.take(j)},rn(be.prototype,function(e,t){var n=/^(?:filter|find|map|reject)|While$/.test(t),i=/^(?:head|last)$/.test(t),h=w[i?"take"+(t=="last"?"Right":""):t],v=i||/^find/.test(t);h&&(w.prototype[t]=function(){var b=this.__wrapped__,R=i?[1]:arguments,O=b instanceof be,q=R[0],H=O||he(b),Z=function(ve){var Ee=h.apply(w,yn([ve],R));return i&&X?Ee[0]:Ee};H&&n&&typeof q=="function"&&q.length!=1&&(O=H=!1);var X=this.__chain__,ne=!!this.__actions__.length,ue=v&&!X,pe=O&&!ne;if(!v&&H){b=pe?b:new be(this);var ae=e.apply(b,R);return ae.__actions__.push({func:C1,args:[Z],thisArg:s}),new Ut(ae,X)}return ue&&pe?e.apply(this,R):(ae=this.thru(Z),ue?i?ae.value()[0]:ae.value():ae)})}),Ft(["pop","push","shift","sort","splice","unshift"],function(e){var t=$i[e],n=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",i=/^(?:pop|shift)$/.test(e);w.prototype[e]=function(){var h=arguments;if(i&&!this.__chain__){var v=this.value();return t.apply(he(v)?v:[],h)}return this[n](function(b){return t.apply(he(b)?b:[],h)})}}),rn(be.prototype,function(e,t){var n=w[t];if(n){var i=n.name+"";Ne.call(Rr,i)||(Rr[i]=[]),Rr[i].push({name:t,func:n})}}),Rr[f1(s,se).name]=[{name:"wrapper",func:s}],be.prototype.clone=A4,be.prototype.reverse=T4,be.prototype.value=R4,w.prototype.at=e8,w.prototype.chain=t8,w.prototype.commit=n8,w.prototype.next=r8,w.prototype.plant=o8,w.prototype.reverse=s8,w.prototype.toJSON=w.prototype.valueOf=w.prototype.value=l8,w.prototype.first=w.prototype.head,oi&&(w.prototype[oi]=i8),w},Ln=n4();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Ve._=Ln,define(function(){return Ln})):er?((er.exports=Ln)._=Ln,t2._=Ln):Ve._=Ln}).call(Ir)});var Fn=we(Qt=>{"use strict";var A9=Qt&&Qt.__importDefault||function(s){return s&&s.__esModule?s:{default:s}};Object.defineProperty(Qt,"__esModule",{value:!0});Qt.Value=Qt.Arity=Qt.FloatOrMilliseconds=void 0;var Ei=A9(f3()),T9=Wr(),R9=new RegExp("[1-9][0-9]{3}-[01][0-9]-[0-3][0-9][T ][0-2][0-9]:[0-5][0-9]"),x9=new RegExp("^-?[0-9]+:[0-5][0-9]"),y9=s=>{let r=s.trim();if(r==="")return new Ei.default(0);if(R9.test(r))return new Ei.default(new Date(r).valueOf());if(x9.test(r)){let c=r.charAt(0)=="-",d=r.slice(c?1:0),C=parseInt(d.slice(0,-3))*60+parseInt(d.slice(-2));return new Ei.default((c?-1:1)*C*6e4)}let l=new Ei.default(r);return l.isNaN()?new Ei.default(0):l};Qt.FloatOrMilliseconds=y9;var H1=class{constructor(r,l){this.isRow=()=>this.rows>1&&this.cols===1,this.isColumn=()=>this.rows===1&&this.cols>1,this.isCell=()=>this.rows===1&&this.cols===1,this.rows=r,this.cols=l}};Qt.Arity=H1;var h3=class{constructor(r){this.get=(l,c)=>this.val[l][c],this.getAsNumber=(l,c)=>{let d=this.get(l,c);return(0,Qt.FloatOrMilliseconds)(d)},this.getArity=()=>{let l=this.val.reduce((c,d)=>Math.max(c,d.length),0);return new H1(this.val.length,l)},this.toString=()=>this.getArity().isCell()?this.get(0,0):`[${(0,T9.flatten)(this.val).map(l=>l.trim()).filter(l=>l!=="").join(", ")}]`,this.val=r}};Qt.Value=h3});var Rl=we($1=>{"use strict";Object.defineProperty($1,"__esModule",{value:!0});$1.AlgebraicOperation=void 0;var ar=Xt(),d3=$t(),Tl=Ai(),B1=Fn(),z1=Wr(),g3=class{constructor(r,l){this.getValue=(_,m)=>{switch(this.operator){case"+":return this.add(_,m);case"-":return this.subtract(_,m);case"*":return this.multiply(_,m);case"/":return this.divide(_,m);default:return(0,ar.err)(Error("Invalid algbraic operator: "+this.operator))}},this.withCellAndRange=(_,m,A,P,y)=>{let S=this.leftSource.getValue(_,m);if(S.isErr())return(0,ar.err)(S.error);let V=this.rightSource.getValue(_,m);if(V.isErr())return(0,ar.err)(V.error);let M=S.value.getArity(),Y=V.value.getArity();if(!Y.isCell()&&!M.isCell())return(0,ar.err)(Error(`At least one operand in algebraic "${A}" must be a single cell.`));if(!Y.isCell()&&!P)return(0,ar.err)(Error(`Right operand in algebraic "${A}" must be a single cell.`));if(Y.isCell()){let D=V.value.getAsNumber(0,0),$=(0,z1.map)(S.value.val,U=>(0,z1.map)(U,K=>{let te=(0,B1.FloatOrMilliseconds)(K);return y(te,D).toString()}));return(0,ar.ok)(new B1.Value($))}let se=S.value.getAsNumber(0,0),ge=(0,z1.map)(V.value.val,D=>(0,z1.map)(D,$=>{let U=(0,B1.FloatOrMilliseconds)($);return y(se,U).toString()}));return(0,ar.ok)(new B1.Value(ge))},this.add=(_,m)=>this.withCellAndRange(_,m,"add",!0,(A,P)=>A.plus(P)),this.subtract=(_,m)=>this.withCellAndRange(_,m,"subtract",!0,(A,P)=>A.minus(P)),this.multiply=(_,m)=>this.withCellAndRange(_,m,"multiply",!0,(A,P)=>A.times(P)),this.divide=(_,m)=>this.withCellAndRange(_,m,"divide",!1,(A,P)=>A.dividedBy(P));let c=(0,d3.checkType)(r,"algebraic_operation");if(c)throw c;let d=(0,d3.checkChildLength)(r,3);if(d)throw d;let C=(0,d3.checkType)(r.children[1],"algebraic_operator");if(C)throw C;this.operator=r.children[1].text;try{this.leftSource=new Tl.Source(r.children[0],l),this.rightSource=new Tl.Source(r.children[2],l)}catch(_){throw _}}};$1.AlgebraicOperation=g3});var xl=we(G1=>{"use strict";Object.defineProperty(G1,"__esModule",{value:!0});G1.ConditionalFunctionCall=void 0;var jt=Xt(),Ti=$t(),Z1=Ai(),p3=class{constructor(r,l){this.getValue=(C,_)=>this.predicate.eval(C,_).andThen(m=>m?this.leftSource.getValue(C,_):this.rightSource.getValue(C,_));let c=(0,Ti.checkType)(r,"conditional_function_call");if(c)throw c;let d=(0,Ti.checkChildLength)(r,3);if(d)throw d;try{this.predicate=new m3(r.children[0],l),this.leftSource=new Z1.Source(r.children[1],l),this.rightSource=new Z1.Source(r.children[2],l)}catch(C){throw C}}};G1.ConditionalFunctionCall=p3;var m3=class{constructor(r,l){this.eval=(_,m)=>{let A=this.leftSource.getValue(_,m);if(A.isErr())return(0,jt.err)(A.error);let P=this.rightSource.getValue(_,m);if(P.isErr())return(0,jt.err)(P.error);let y=A.value.getArity(),S=P.value.getArity();if(!y.isCell())return(0,jt.err)(Error("Can only use comparison operator on a single cell. Left side is not a cell."));if(!S.isCell())return(0,jt.err)(Error("Can only use comparison operator on a single cell. Right side is not a cell."));let V=A.value.getAsNumber(0,0),M=P.value.getAsNumber(0,0);switch(this.operator){case">":return(0,jt.ok)(V.greaterThan(M));case">=":return(0,jt.ok)(V.greaterThanOrEqualTo(M));case"<":return(0,jt.ok)(V.lessThan(M));case"<=":return(0,jt.ok)(V.lessThanOrEqualTo(M));case"==":return(0,jt.ok)(V.equals(M));case"!=":return(0,jt.ok)(!V.equals(M));default:return(0,jt.err)(Error("Invalid conditional operator: "+this.operator))}};let c=(0,Ti.checkType)(r,"predicate");if(c)throw c;let d=(0,Ti.checkChildLength)(r,3);if(d)throw d;let C=(0,Ti.checkType)(r.children[1],"conditional_operator");if(C)throw C;this.operator=r.children[1].text;try{this.leftSource=new Z1.Source(r.children[0],l),this.rightSource=new Z1.Source(r.children[2],l)}catch(_){throw _}}}});var yl=we(V1=>{"use strict";Object.defineProperty(V1,"__esModule",{value:!0});V1.Constant=void 0;var N9=Xt(),L9=$t(),O9=Fn(),w3=class{constructor(r,l){let c=(0,L9.checkType)(r,"real","float");if(c)throw c;let d=r.text[0]==="-"?-1:1;r.type==="real"?this.value=d*parseInt(r.children[0].text):this.value=d*parseFloat(r.children[0].text+"."+r.children[1].text)}getValue(r,l){return(0,N9.ok)(new O9.Value([[this.value.toString()]]))}};V1.Constant=w3});var v3=we(Un=>{"use strict";Object.defineProperty(Un,"__esModule",{value:!0});Un.AbsoluteColumn=Un.Column=Un.newColumn=void 0;var kn=Xt(),Ri=$t(),S9=Fn(),P9=(s,r)=>{try{switch(s.type){case"relative_column":return(0,kn.ok)(new C3(s,r));case"absolute_column":return(0,kn.ok)(new K1(s,r));default:return(0,kn.err)(new Error(`Formula element '${s.text}' is a ${s.type} but expected an relatve_column or absolute_column in this position.`))}}catch(l){return(0,kn.err)(l)}};Un.newColumn=P9;var xi=class{constructor(){this.getValue=(r,l)=>{var c;let d=((c=r.getCellAt(l.row,this.getIndex(l)))===null||c===void 0?void 0:c.toText())||"";return(0,kn.ok)(new S9.Value([[d]]))}}};Un.Column=xi;var C3=class extends xi{constructor(r,l){super(),this.getIndex=_=>_.column+this.offset,this.getAbsoluteIndex=()=>(0,kn.err)(Ri.errRelativeReferenceIndex);let c=(0,Ri.checkType)(r,"relative_column");if(c)throw c;let d=(0,Ri.checkChildLength)(r,1);if(d)throw d;let C=r.text[1]==="-"?-1:1;this.offset=C*parseInt(r.children[0].text)}},K1=class extends xi{constructor(r,l){super(),this.getIndex=C=>this.index,this.getAbsoluteIndex=()=>(0,kn.ok)(this.index);let c=-1,d="";switch(r.children.length){case 0:d=r.text[1];break;case 1:let C=(0,Ri.checkType)(r.children[0],"int");if(C)throw(0,kn.err)(C);c=parseInt(r.children[0].text);break;default:throw new Error(`Formula element '${r.text}' is a ${r.type} but expected a 'absolute_column' in this position.`)}switch(d){case"":break;case"<":c=1;break;case">":c=l.getWidth();break;default:throw new Error(`Invalid column symbol '${d}'`)}if(c===0)throw Ri.errIndex0;this.index=c-1}};Un.AbsoluteColumn=K1});var b3=we(Hn=>{"use strict";Object.defineProperty(Hn,"__esModule",{value:!0});Hn.AbsoluteRow=Hn.Row=Hn.newRow=void 0;var qn=Xt(),yi=$t(),I9=Fn(),W9=(s,r)=>{try{switch(s.type){case"relative_row":return(0,qn.ok)(new _3(s,r));case"absolute_row":return(0,qn.ok)(new Y1(s,r));default:return(0,qn.err)(new Error(`Formula element '${s.text}' is a ${s.type} but expected an relatve_row or absolute_row in this position.`))}}catch(l){return(0,qn.err)(l)}};Hn.newRow=W9;var Ni=class{constructor(){this.getValue=(r,l)=>{var c;let d=((c=r.getCellAt(this.getIndex(l),l.column))===null||c===void 0?void 0:c.toText())||"";return(0,qn.ok)(new I9.Value([[d]]))}}};Hn.Row=Ni;var _3=class extends Ni{constructor(r,l){super(),this.getIndex=_=>_.row+this.offset,this.getAbsoluteIndex=()=>(0,qn.err)(yi.errRelativeReferenceIndex);let c=(0,yi.checkType)(r,"relative_row");if(c)throw c;let d=(0,yi.checkChildLength)(r,1);if(d)throw d;let C=r.text[1]==="-"?-1:1;this.offset=C*parseInt(r.children[0].text)}},Y1=class extends Ni{constructor(r,l){super(),this.getIndex=C=>this.index,this.getAbsoluteIndex=()=>(0,qn.ok)(this.index);let c=-1,d="";switch(r.children.length){case 0:d=r.text[1];break;case 1:let C=(0,yi.checkType)(r.children[0],"int");if(C)throw(0,qn.err)(C);c=parseInt(r.children[0].text);break;default:throw new Error(`Formula element '${r.text}' is a ${r.type} but expected a 'absolute_row' in this position.`)}switch(d){case"":break;case"<":c=1;break;case">":c=l.getHeight()-1;break;case"I":c=2;break;default:throw new Error(`Invalid row symbol '${d}'`)}if(c===0)throw yi.errIndex0;c===1?this.index=0:this.index=c}};Hn.AbsoluteRow=Y1});var T3=we(J1=>{"use strict";Object.defineProperty(J1,"__esModule",{value:!0});J1.Reference=void 0;var M9=Xt(),E3=$t(),D9=v3(),F9=Fn(),k9=b3(),A3=class{constructor(r,l){this.getValue=(d,C)=>{var _;let m={row:this.row?this.row.getIndex(C):C.row,column:this.column?this.column.getIndex(C):C.column},A=((_=d.getCellAt(m.row,m.column))===null||_===void 0?void 0:_.toText())||"";return(0,M9.ok)(new F9.Value([[A]]))};let c=(0,E3.checkType)(r,"source_reference","absolute_reference","relative_reference");if(c)throw c;for(let d=0;d{"use strict";Object.defineProperty(Q1,"__esModule",{value:!0});Q1.Range=void 0;var X1=Xt(),Mr=$t(),Nl=T3(),U9=Fn(),cr=Wr(),R3=class{constructor(r,l){this.getValue=(P,y)=>{let S=this.startColumn?this.startColumn.getIndex(y):y.column,V=this.endColumn?this.endColumn.getIndex(y):S,M=this.startRow?this.startRow.getIndex(y):y.row,Y=this.endRow?this.endRow.getIndex(y):y.row;return(0,X1.ok)(new U9.Value((0,cr.map)((0,cr.range)(M,Y+1),se=>(0,cr.map)((0,cr.range)(S,V+1),ge=>{var D;return((D=P.getCellAt(se,ge))===null||D===void 0?void 0:D.toText())||""}))))},this.asCells=()=>{if(!this.startColumn||!this.startRow||!this.endRow)return(0,X1.err)(new Error("A range used as a desintation must define rows and cells"));let P=this.endColumn;P||(P=this.startColumn);let y=this.startRow.getAbsoluteIndex(),S=this.endRow.getAbsoluteIndex(),V=this.startColumn.getAbsoluteIndex(),M=P.getAbsoluteIndex();if(y.isErr()||S.isErr()||V.isErr()||M.isErr())return(0,X1.err)(new Error("A relative range can not be used in a formula destination"));let Y=Math.min(y.value,S.value),se=Math.max(y.value,S.value),ge=Math.min(V.value,M.value),D=Math.max(V.value,M.value);return(0,X1.ok)((0,cr.flatMap)((0,cr.range)(Y,se+1),$=>(0,cr.range)(ge,D+1).map(U=>({row:$,column:U}))))};let c=(0,Mr.checkType)(r,"range");if(c)throw c;let d=(0,Mr.checkChildLength)(r,2);if(d)throw d;let C=r.children[0],_=r.children[1];if(c=(0,Mr.checkType)(C,"source_reference"),c||(c=(0,Mr.checkType)(_,"source_reference"),c))throw c;if(d=(0,Mr.checkChildLength)(C,1),d||(d=(0,Mr.checkChildLength)(_,1),d))throw d;let m=new Nl.Reference(C.children[0],l),A=new Nl.Reference(_.children[0],l);if(m.row&&!A.row||A.row&&!m.row)throw new Error("Range must use references of the same kind");if(!m.row&&!m.column)throw console.log(m),new Error("Range must have a row or a column defined");m.row&&(this.startRow=m.row),m.column&&(this.startColumn=m.column),A.row&&(this.endRow=A.row),A.column?this.endColumn=A.column:this.endColumn=m.column}};Q1.Range=R3});var Pl=we(Zt=>{"use strict";Object.defineProperty(Zt,"__esModule",{value:!0});Zt.RangeDestination=Zt.CellDestination=Zt.ColumnDestination=Zt.RowDestination=Zt.newDestination=void 0;var Pt=Xt(),wt=$t(),Ll=v3(),q9=x3(),Ol=b3(),Sl=Wr(),H9=(s,r,l)=>{let c=(0,wt.checkType)(s,"destination");if(c)return(0,Pt.err)(c);let d=(0,wt.checkChildLength)(s,1);if(d)return(0,Pt.err)(d);let C=s.children[0];if(C.type==="range")return(0,Pt.ok)(new no(C,r,l));try{switch(C.children.length){case 2:return(0,Pt.ok)(new to(C,r,l));case 1:let _=C.children[0];if(_.type==="absolute_row")return(0,Pt.ok)(new j1(C,r,l));if(_.type==="absolute_column")return(0,Pt.ok)(new eo(C,r,l));default:return(0,Pt.err)(new Error("Unexpected destination type "+C.type))}}catch(_){return _===wt.errIndex0?(0,Pt.err)(new Error("Index 0 may not be used in a destination")):(0,Pt.err)(_)}};Zt.newDestination=H9;var j1=class{constructor(r,l,c){this.merge=(m,A)=>{let P=(0,Sl.range)(0,A.getWidth()).map(y=>({row:this.row.index,column:y}));return ro(m,A,P,this.formatter)},this.formatter=c;let d=(0,wt.checkType)(r,"absolute_reference");if(d)throw d;let C=(0,wt.checkChildLength)(r,1);if(C)throw C;let _=r.children[0];try{this.row=new Ol.AbsoluteRow(_,l)}catch(m){throw m}}};Zt.RowDestination=j1;var eo=class{constructor(r,l,c){this.merge=(m,A)=>{let P=(0,Sl.range)(2,A.getHeight()).map(y=>({row:y,column:this.column.index}));return ro(m,A,P,this.formatter)},this.formatter=c;let d=(0,wt.checkType)(r,"absolute_reference");if(d)throw d;let C=(0,wt.checkChildLength)(r,1);if(C)throw C;let _=r.children[0];try{this.column=new Ll.AbsoluteColumn(_,l)}catch(m){throw m}}};Zt.ColumnDestination=eo;var to=class{constructor(r,l,c){this.merge=(A,P)=>{let y={row:this.row.index,column:this.column.index};return ro(A,P,[y],this.formatter)},this.formatter=c;let d=(0,wt.checkType)(r,"absolute_reference");if(d)throw d;let C=(0,wt.checkChildLength)(r,2);if(C)throw C;let _=r.children[0],m=r.children[1];try{this.row=new Ol.AbsoluteRow(_,l),this.column=new Ll.AbsoluteColumn(m,l)}catch(A){throw A}}};Zt.CellDestination=to;var no=class{constructor(r,l,c){this.merge=(_,m)=>this.range.asCells().andThen(A=>ro(_,m,A,this.formatter)),this.formatter=c;let d=(0,wt.checkType)(r,"range");if(d)throw d;let C=(0,wt.checkChildLength)(r,2);if(C)throw C;r.children.forEach(_=>{let m=(0,wt.checkType)(_,"source_reference");if(m)throw m;let A=(0,wt.checkChildLength)(_,1);if(A)throw A;if(m=(0,wt.checkType)(_.children[0],"absolute_reference"),m)throw m}),this.range=new q9.Range(r,l)}};Zt.RangeDestination=no;var ro=(s,r,l,c)=>l.reduce((d,C)=>d.andThen(_=>s.getValue(_,C).andThen(m=>(0,Pt.ok)(m.toString())).andThen(m=>(0,Pt.ok)(m.trim()===""?"0":m)).andThen(m=>(0,Pt.ok)(_.setCellAt(C.row,C.column,c.format(m))))),(0,Pt.ok)(r))});var Il=we(Dr=>{"use strict";Object.defineProperty(Dr,"__esModule",{value:!0});Dr.DisplayDirective=Dr.DefaultFormatter=void 0;var fr=$t(),y3=class{constructor(){this.format=r=>typeof r=="string"?r:r.toString()}};Dr.DefaultFormatter=y3;var N3=class{constructor(r){this.format=m=>{let A=typeof m=="string"?parseFloat(m):m;if(this.displayAsDatetime){let P=new Date(A),y=ge=>`0${ge}`.slice(-2),S=P.getFullYear(),V=y(P.getMonth()+1),M=y(P.getDate()),Y=y(P.getHours()),se=y(P.getMinutes());return`${S}-${V}-${M} ${Y}:${se}`}if(this.displayAsHourMinute){let P=A<0?"-":"",y=Math.floor(Math.abs(A)/6e4),S=Y=>`0${Y}`.slice(-2),V=S(Math.floor(y/60)),M=S(y%60);return`${P}${V}:${M}`}return A.toFixed(this.decimalLength)};let l=(0,fr.checkType)(r,"display_directive");if(l)throw l;let c=(0,fr.checkChildLength)(r,1);if(c)throw c;let d=r.children[0];if(l=(0,fr.checkType)(d,"display_directive_option"),l)throw l;if(c=(0,fr.checkChildLength)(d,1),c)throw c;let C=d.children[0];if(l=(0,fr.checkType)(C,"formatting_directive","datetime_directive","hourminute_directive"),l)throw l;if(this.displayAsDatetime=C.type==="datetime_directive",this.displayAsHourMinute=C.type==="hourminute_directive",this.displayAsDatetime||this.displayAsHourMinute){this.decimalLength=-1;return}if(c=(0,fr.checkChildLength)(C,1),c)throw c;let _=C.children[0];if(l=(0,fr.checkType)(_,"int"),l)throw l;this.decimalLength=parseInt(_.text)}};Dr.DisplayDirective=N3});var Wl=we(Fr=>{"use strict";var B9=Fr&&Fr.__importDefault||function(s){return s&&s.__esModule?s:{default:s}};Object.defineProperty(Fr,"__esModule",{value:!0});Fr.SingleParamFunctionCall=void 0;var z9=Xt(),L3=$t(),$9=Ai(),O3=Fn(),Z9=B9(f3()),S3=class{constructor(r,l){this.getValue=(m,A)=>this.param.getValue(m,A).andThen(P=>(0,z9.ok)(this.op(P)));let c=(0,L3.checkType)(r,"single_param_function_call");if(c)throw c;let d=(0,L3.checkChildLength)(r,2);if(d)throw d;let C=(0,L3.checkType)(r.children[0],"single_param_function");if(C)throw C;let _=r.children[0].text;switch(_){case"sum":this.op=G9;break;case"mean":this.op=V9;break;default:throw Error("Unknown single param function call: "+_)}this.param=new $9.Source(r.children[1],l)}};Fr.SingleParamFunctionCall=S3;var G9=s=>{let r=s.val.reduce((l,c)=>c.reduce((d,C)=>(0,O3.FloatOrMilliseconds)(C).add(d),l),new Z9.default(0));return new O3.Value([[r.toString()]])},V9=s=>{let{total:r,count:l}=s.val.reduce(({total:c,count:d},C)=>C.reduce(({total:_,count:m},A)=>({total:_+ +A,count:m+1}),{total:c,count:d}),{total:0,count:0});return new O3.Value([[(r/l).toString()]])}});var oo=we(io=>{"use strict";Object.defineProperty(io,"__esModule",{value:!0});io.TokenError=void 0;var P3=class extends Error{constructor(r,l){if(super(r),this.message=r,this.token=l,l&&l.errors)l.errors.push(this);else throw this}inspect(){return"SyntaxError: "+this.message}};io.TokenError=P3});var Li=we(It=>{"use strict";Object.defineProperty(It,"__esModule",{value:!0});It.Parser=It.findRuleByName=It.parseRuleName=It.escapeRegExp=It.readToken=void 0;var Ml=/^[A-Z0-9_]+$/,Dl=/(\?|\+|\*)$/,Fl=/^(@|&|!)/,so="WS",lo=oo();function I3(s,r){let l=r.exec(s);return l&&l.index==0?l[0].length==0&&r.source.length>0?null:{type:null,text:l[0],rest:s.substr(l[0].length),start:0,end:l[0].length-1,fullText:l[0],errors:[],children:[],parent:null}:null}It.readToken=I3;function kl(s){return s.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}It.escapeRegExp=kl;function Ul(s){s.rest="",s.children&&s.children.forEach(r=>Ul(r))}function ql(s,r){s.start+=r,s.end+=r,s.children&&s.children.forEach(l=>ql(l,s.start))}function Hl(s,r){r.errors&&r.errors.length&&r.errors.forEach(l=>s.push(l)),r.children&&r.children.forEach(l=>Hl(s,l))}function hr(s){let r=Dl.exec(s),l=Fl.exec(s),c=r&&r[0]||"",d=l&&l[0]||"",C={raw:s,name:s.replace(Dl,"").replace(Fl,""),isOptional:c=="?"||c=="*",allowRepetition:c=="+"||c=="*",atLeastOne:c=="+",lookupPositive:d=="&",lookupNegative:d=="!",pinned:d=="@",lookup:!1,isLiteral:!1};return C.isLiteral=C.name[0]=="'"||C.name[0]=='"',C.lookup=C.lookupNegative||C.lookupPositive,C}It.parseRuleName=hr;function Bl(s,r){let l=hr(s);return r.cachedRules[l.name]||null}It.findRuleByName=Bl;function W3(s,r){if(s.children){let l=s.children.filter(c=>c.type&&r.test(c.type));for(let c=0;cW3(c,r))}}var K9=["EOF"],uo=class{constructor(r,l){this.grammarRules=r,this.options=l,this.cachedRules={},this.debug=l?l.debug===!0:!1;let c=[],d=[];if(r.forEach(C=>{let _=hr(C.name);if(_.name in this.cachedRules){c.push("Duplicated rule "+_.name);return}else this.cachedRules[_.name]=C;if(!C.bnf||!C.bnf.length){let m="Missing rule content, rule: "+C.name;c.indexOf(m)==-1&&c.push(m)}else C.bnf.forEach(m=>{if(typeof m[0]=="string"&&hr(m[0]).name==C.name){let P="Left recursion is not allowed, rule: "+C.name;c.indexOf(P)==-1&&c.push(P)}m.forEach(A=>{if(typeof A=="string"){let P=hr(A);!P.isLiteral&&d.indexOf(P.name)==-1&&K9.indexOf(P.name)==-1&&d.push(P.name)}})});so==C.name&&(C.implicitWs=!1),C.implicitWs&&d.indexOf(so)==-1&&d.push(so),C.recover&&d.indexOf(C.recover)==-1&&d.push(C.recover)}),d.forEach(C=>{C in this.cachedRules||c.push("Missing rule "+C)}),c.length)throw new Error(c.join(` +`))}getAST(r,l){l||(l=this.grammarRules.filter(d=>!d.fragment&&d.name.indexOf("%")!=0)[0].name);let c=this.parse(r,l);if(c){Hl(c.errors,c),ql(c,0),W3(c,/^%/),(!this.options||!this.options.keepUpperRules)&&W3(c,Ml);let d=c.rest;d&&new lo.TokenError(`Unexpected end of input: +`+d,c),Ul(c),c.rest=d}return c}emitSource(){return"CANNOT EMIT SOURCE FROM BASE Parser"}parse(r,l,c=0){let d=null,C=hr(l),_,m=this.debug&&!Ml.test(C.name);m&&console.log(new Array(c).join("\u2502 ")+"Trying to get "+l+" from "+JSON.stringify(r.split(` +`)[0]));let A=C.name,P=Bl(C.name,this);if(C.name=="EOF"){if(r.length)return null;if(r.length==0)return{type:"EOF",text:"",rest:"",start:0,end:0,fullText:"",errors:[],children:[],parent:null}}try{if(!P&&C.isLiteral){let y=C.name.trim();if(y.startsWith('"')?y=JSON.parse(y):y.startsWith("'")&&(y=y.replace(/^'(.+)'$/,"$1").replace(/\\'/g,"'")),y==="")return{type:"%%EMPTY%%",text:"",rest:r,start:0,end:0,fullText:"",errors:[],children:[],parent:null};_=new RegExp(kl(y)),A=null}}catch(y){return y instanceof ReferenceError&&console.error(y),null}if(_){let y=I3(r,_);if(y)return y.type=A,y}else{let y=P.bnf;y instanceof Array&&y.forEach(S=>{if(d)return;let V=null,M={type:C.name,text:"",children:[],end:0,errors:[],fullText:"",parent:null,start:0,rest:r};P.fragment&&(M.fragment=!0);let Y=r,se=0,ge=S.length>0,D=!1;for(let $=0;${J.start+=se,J.end+=se,J.parent=M,M.children.push(J)}):(K.parent=M,M.children.push(K))),U.lookup&&(K.lookup=!0),m&&console.log(new Array(c+1).join("\u2502 ")+"\u2514\u2500 "+K.type+" "+JSON.stringify(K.text)),!U.lookup&&!K.lookup&&(M.text=M.text+K.text,M.end=M.text.length,Y=Y.substr(K.text.length),se+=K.text.length),M.rest=Y}while(K&&U.allowRepetition&&Y.length&&!K.lookup)}else{let U=I3(Y,S[$]);if(!U)return;m&&console.log(new Array(c+1).join("\u2502 ")+"\u2514> "+JSON.stringify(U.text)+S[$].source),D=!0,U.start+=se,U.end+=se,M.text=M.text+U.text,M.end=M.text.length,Y=Y.substr(U.text.length),se+=U.text.length,M.rest=Y}D&&(d=M,m&&console.log(new Array(c).join("\u2502 ")+"\u251C<\u2500\u2534< PUSHING "+d.type+" "+JSON.stringify(d.text)))}),d&&P.simplifyWhenOneChildren&&d.children.length==1&&(d=d.children[0])}return d||m&&console.log(l+" NOT RESOLVED FROM "+r),d}parseRecovery(r,l,c){if(r.recover&&l.length){let d=this.debug;d&&console.log(new Array(c+1).join("\u2502 ")+"Trying to recover until token "+r.recover+" from "+JSON.stringify(l.split(` +`)[0]+l.split(` +`)[1]));let C={type:"SyntaxError",text:"",children:[],end:0,errors:[],fullText:"",parent:null,start:0,rest:""},_;do if(_=this.parse(l,r.recover,c+1),_){new lo.TokenError('Unexpected input: "'+C.text+`" Expecting: ${r.name}`,C);break}else C.text=C.text+l[0],C.end=C.text.length,l=l.substr(1);while(!_&&l.length>0);if(C.text.length>0&&_)return d&&console.log(new Array(c+1).join("\u2502 ")+"Recovered text: "+JSON.stringify(C.text)),C}return null}};It.Parser=uo;It.default=uo});var zl=we(ao=>{"use strict";Object.defineProperty(ao,"__esModule",{value:!0});ao.findChildrenByType=void 0;function Y9(s,r){return s.children?s.children.filter(l=>l.type==r):[]}ao.findChildrenByType=Y9});var $l=we(F3=>{"use strict";Object.defineProperty(F3,"__esModule",{value:!0});var Bn=zl(),M3=Li(),D3;(function(s){s.RULES=[{name:"syntax",bnf:[["RULE_EOL*","rule+"]]},{name:"rule",bnf:[['" "*','"<"',"rule-name",'">"','" "*','"::="',"firstExpression","otherExpression*",'" "*',"RULE_EOL+",'" "*']]},{name:"firstExpression",bnf:[['" "*',"list"]]},{name:"otherExpression",bnf:[['" "*','"|"','" "*',"list"]]},{name:"RULE_EOL",bnf:[['"\\r"'],['"\\n"']]},{name:"list",bnf:[["term",'" "*',"list"],["term"]]},{name:"term",bnf:[["literal"],['"<"',"rule-name",'">"']]},{name:"literal",bnf:[[`'"'`,"RULE_CHARACTER1*",`'"'`],[`"'"`,"RULE_CHARACTER2*",`"'"`]]},{name:"RULE_CHARACTER",bnf:[['" "'],["RULE_LETTER"],["RULE_DIGIT"],["RULE_SYMBOL"]]},{name:"RULE_LETTER",bnf:[['"A"'],['"B"'],['"C"'],['"D"'],['"E"'],['"F"'],['"G"'],['"H"'],['"I"'],['"J"'],['"K"'],['"L"'],['"M"'],['"N"'],['"O"'],['"P"'],['"Q"'],['"R"'],['"S"'],['"T"'],['"U"'],['"V"'],['"W"'],['"X"'],['"Y"'],['"Z"'],['"a"'],['"b"'],['"c"'],['"d"'],['"e"'],['"f"'],['"g"'],['"h"'],['"i"'],['"j"'],['"k"'],['"l"'],['"m"'],['"n"'],['"o"'],['"p"'],['"q"'],['"r"'],['"s"'],['"t"'],['"u"'],['"v"'],['"w"'],['"x"'],['"y"'],['"z"']]},{name:"RULE_DIGIT",bnf:[['"0"'],['"1"'],['"2"'],['"3"'],['"4"'],['"5"'],['"6"'],['"7"'],['"8"'],['"9"']]},{name:"RULE_SYMBOL",bnf:[['"-"'],['"_"'],['"!"'],['"#"'],['"$"'],['"%"'],['"&"'],['"("'],['")"'],['"*"'],['"+"'],['","'],['"-"'],['"."'],['"/"'],['":"'],['";"'],['"<"'],['"="'],['">"'],['"?"'],['"@"'],['"["'],['"\\"'],['"]"'],['"^"'],['"_"'],['"`"'],['"{"'],['"|"'],['"}"'],['"~"']]},{name:"RULE_CHARACTER1",bnf:[["RULE_CHARACTER"],[`"'"`]]},{name:"RULE_CHARACTER2",bnf:[["RULE_CHARACTER"],[`'"'`]]},{name:"rule-name",bnf:[["RULE_LETTER","RULE_CHAR*"]]},{name:"RULE_CHAR",bnf:[["RULE_LETTER"],["RULE_DIGIT"],['"_"'],['"-"']]}],s.defaultParser=new M3.Parser(s.RULES,{debug:!1});function r(C){let _=Bn.findChildrenByType(C,"term").map(m=>Bn.findChildrenByType(m,"literal").concat(Bn.findChildrenByType(m,"rule-name"))[0].text);return Bn.findChildrenByType(C,"list").forEach(m=>{_=_.concat(r(m))}),_}function l(C,_=s.defaultParser){let m=_.getAST(C);if(!m)throw new Error("Could not parse "+C);if(m.errors&&m.errors.length)throw m.errors[0];let P=Bn.findChildrenByType(m,"rule").map(y=>{let S=Bn.findChildrenByType(y,"rule-name")[0].text,V=Bn.findChildrenByType(y,"firstExpression").concat(Bn.findChildrenByType(y,"otherExpression")),M=[];return V.forEach(Y=>{M.push(r(Y))}),{name:S,bnf:M}});return P.some(y=>y.name=="EOL")||P.push({name:"EOL",bnf:[['"\\r\\n"','"\\r"','"\\n"']]}),P}s.getRules=l;function c(C,_=s.defaultParser){return l(C.join(""),_)}s.Transform=c;class d extends M3.Parser{constructor(_,m){let A=m&&m.debugRulesParser===!0?new M3.Parser(s.RULES,{debug:!0}):s.defaultParser;super(l(_,A),m),this.source=_}emitSource(){return this.source}}s.Parser=d})(D3||(D3={}));F3.default=D3});var Zl=we(U3=>{"use strict";Object.defineProperty(U3,"__esModule",{value:!0});var Oi=Li(),k3;(function(s){s.RULES=[{name:"Grammar",bnf:[["RULE_S*","%Atomic*","EOF"]]},{name:"%Atomic",bnf:[["Production","RULE_S*"]],fragment:!0},{name:"Production",bnf:[["NCName","RULE_S*",'"::="',"RULE_WHITESPACE*","Choice","RULE_WHITESPACE*","RULE_EOL+","RULE_S*"]]},{name:"NCName",bnf:[[/[a-zA-Z][a-zA-Z_0-9]*/]]},{name:"Choice",bnf:[["SequenceOrDifference","%_Choice_1*"]],fragment:!0},{name:"%_Choice_1",bnf:[["RULE_WHITESPACE*",'"|"',"RULE_WHITESPACE*","SequenceOrDifference"]],fragment:!0},{name:"SequenceOrDifference",bnf:[["Item","RULE_WHITESPACE*","%_Item_1?"]]},{name:"%_Item_1",bnf:[["Minus","Item"],["Item*"]],fragment:!0},{name:"Minus",bnf:[['"-"']]},{name:"Item",bnf:[["RULE_WHITESPACE*","%Primary","PrimaryDecoration?"]],fragment:!0},{name:"PrimaryDecoration",bnf:[['"?"'],['"*"'],['"+"']]},{name:"DecorationName",bnf:[['"ebnf://"',/[^\x5D#]+/]]},{name:"%Primary",bnf:[["NCName"],["StringLiteral"],["CharCode"],["CharClass"],["SubItem"]],fragment:!0},{name:"SubItem",bnf:[['"("',"RULE_WHITESPACE*","Choice","RULE_WHITESPACE*",'")"']]},{name:"StringLiteral",bnf:[[`'"'`,/[^"]*/,`'"'`],[`"'"`,/[^']*/,`"'"`]],pinned:1},{name:"CharCode",bnf:[['"#x"',/[0-9a-zA-Z]+/]]},{name:"CharClass",bnf:[["'['","'^'?","%RULE_CharClass_1+",'"]"']]},{name:"%RULE_CharClass_1",bnf:[["CharCodeRange"],["CharRange"],["CharCode"],["RULE_Char"]],fragment:!0},{name:"RULE_Char",bnf:[[/\x09/],[/\x0A/],[/\x0D/],[/[\x20-\x5c]/],[/[\x5e-\uD7FF]/],[/[\uE000-\uFFFD]/]]},{name:"CharRange",bnf:[["RULE_Char",'"-"',"RULE_Char"]]},{name:"CharCodeRange",bnf:[["CharCode",'"-"',"CharCode"]]},{name:"RULE_WHITESPACE",bnf:[["%RULE_WHITESPACE_CHAR*"],["Comment","RULE_WHITESPACE*"]]},{name:"RULE_S",bnf:[["RULE_WHITESPACE","RULE_S*"],["RULE_EOL","RULE_S*"]]},{name:"%RULE_WHITESPACE_CHAR",bnf:[[/\x09/],[/\x20/]],fragment:!0},{name:"Comment",bnf:[['"/*"',"%RULE_Comment_Body*",'"*/"']]},{name:"%RULE_Comment_Body",bnf:[['!"*/"',/[^*]/]],fragment:!0},{name:"RULE_EOL",bnf:[[/\x0D/,/\x0A/],[/\x0A/],[/\x0D/]]},{name:"Link",bnf:[["'['","Url","']'"]]},{name:"Url",bnf:[[/[^\x5D:/?#]/,'"://"',/[^\x5D#]+/,"%Url1?"]]},{name:"%Url1",bnf:[['"#"',"NCName"]],fragment:!0}],s.defaultParser=new Oi.Parser(s.RULES,{debug:!1});let r=/^(!|&)/,l=/(\?|\+|\*)$/,c=/^%/;function d(D,$){if(typeof D=="string"){if(r.test(D))return"";if(c.test(D)){let K=l.exec(D),te=K?K[0]+" ":"";return C(D,$)?m(D,$)+te:"("+m(D,$)+")"+te}return D}else return D.source.replace(/\\(?:x|u)([a-zA-Z0-9]+)/g,"#x$1").replace(/\[\\(?:x|u)([a-zA-Z0-9]+)-\\(?:x|u)([a-zA-Z0-9]+)\]/g,"[#x$1-#x$2]")}function C(D,$){let U=Oi.findRuleByName(D,$);return U&&U.bnf.length==1&&U.bnf[0].length==1&&(U.bnf[0][0]instanceof RegExp||U.bnf[0][0][0]=='"'||U.bnf[0][0][0]=="'")}function _(D,$){return D.map(U=>d(U,$)).join(" ")}function m(D,$){let U=Oi.findRuleByName(D,$);return U?U.bnf.map(K=>_(K,$)).join(" | "):"RULE_NOT_FOUND {"+D+"}"}function A(D){let $=[];return D.grammarRules.forEach(U=>{if(!/^%/.test(U.name)){let K=U.recover?" /* { recoverUntil="+U.recover+" } */":"";$.push(U.name+" ::= "+m(U.name,D)+K)}}),$.join(` +`)}s.emit=A;let P=0;function y(D,$){throw console.log("reberia restar "+$+" a "+D),new Error("Difference not supported yet")}function S(D){return new RegExp(D.replace(/#x([a-zA-Z0-9]{4})/g,"\\u$1").replace(/#x([a-zA-Z0-9]{3})/g,"\\u0$1").replace(/#x([a-zA-Z0-9]{2})/g,"\\x$1").replace(/#x([a-zA-Z0-9]{1})/g,"\\x0$1"))}function V(D,$,U){let K=null,te=[];return $.children.forEach((J,Q)=>{J.type=="Minus"&&y(K,J);let G=$.children[Q+1];G=G&&G.type=="PrimaryDecoration"&&G.text||"";let Ce="";switch(J.type){case"SubItem":let Pe="%"+(U+P++);M(D,J,Pe),te.push(Ce+Pe+G);break;case"NCName":case"StringLiteral":te.push(Ce+J.text+G);break;case"CharCode":case"CharClass":if(G||Ce){let ot={name:"%"+(U+P++),bnf:[[S(J.text)]]};D.push(ot),te.push(Ce+ot.name+G)}else te.push(S(J.text));break;case"PrimaryDecoration":break;default:throw new Error(" HOW SHOULD I PARSE THIS? "+J.type+" -> "+JSON.stringify(J.text))}K=J}),te}function M(D,$,U){let K=$.children.filter(Q=>Q.type=="SequenceOrDifference").map(Q=>V(D,Q,U)),te={name:U,bnf:K},J=null;K.forEach(Q=>{J=J||Q.recover,delete Q.recover}),U.indexOf("%")==0&&(te.fragment=!0),J&&(te.recover=J),D.push(te)}function Y(D,$=s.defaultParser){let U=$.getAST(D);if(!U)throw new Error("Could not parse "+D);if(U.errors&&U.errors.length)throw U.errors[0];let K=[];return U.children.filter(te=>te.type=="Production").map(te=>{let J=te.children.filter(Q=>Q.type=="NCName")[0].text;M(K,te,J)}),K}s.getRules=Y;function se(D,$=s.defaultParser){return Y(D.join(""),$)}s.Transform=se;class ge extends Oi.Parser{constructor($,U){let K=U&&U.debugRulesParser===!0?new Oi.Parser(s.RULES,{debug:!0}):s.defaultParser;super(Y($,K),U)}emitSource(){return A(this)}}s.Parser=ge})(k3||(k3={}));U3.default=k3});var Gl=we(H3=>{"use strict";Object.defineProperty(H3,"__esModule",{value:!0});var co=oo(),kr=Li(),q3;(function(s){s.RULES=[{name:"Grammar",bnf:[["RULE_S*","Attributes?","RULE_S*","%Atomic*","EOF"]]},{name:"%Atomic",bnf:[["Production","RULE_S*"]],fragment:!0},{name:"Production",bnf:[["NCName","RULE_S*",'"::="',"RULE_WHITESPACE*","%Choice","RULE_WHITESPACE*","Attributes?","RULE_EOL+","RULE_S*"]]},{name:"NCName",bnf:[[/[a-zA-Z][a-zA-Z_0-9]*/]]},{name:"Attributes",bnf:[['"{"',"Attribute","%Attributes*","RULE_S*",'"}"']]},{name:"%Attributes",bnf:[["RULE_S*",'","',"Attribute"]],fragment:!0},{name:"Attribute",bnf:[["RULE_S*","NCName","RULE_WHITESPACE*",'"="',"RULE_WHITESPACE*","AttributeValue"]]},{name:"AttributeValue",bnf:[["NCName"],[/[1-9][0-9]*/]]},{name:"%Choice",bnf:[["SequenceOrDifference","%_Choice_1*"]],fragment:!0},{name:"%_Choice_1",bnf:[["RULE_S*",'"|"',"RULE_S*","SequenceOrDifference"]],fragment:!0},{name:"SequenceOrDifference",bnf:[["%Item","RULE_WHITESPACE*","%_Item_1?"]]},{name:"%_Item_1",bnf:[["Minus","%Item"],["%Item*"]],fragment:!0},{name:"Minus",bnf:[['"-"']]},{name:"%Item",bnf:[["RULE_WHITESPACE*","PrimaryPreDecoration?","%Primary","PrimaryDecoration?"]],fragment:!0},{name:"PrimaryDecoration",bnf:[['"?"'],['"*"'],['"+"']]},{name:"PrimaryPreDecoration",bnf:[['"&"'],['"!"'],['"~"']]},{name:"%Primary",bnf:[["NCName"],["StringLiteral"],["CharCode"],["CharClass"],["SubItem"]],fragment:!0},{name:"SubItem",bnf:[['"("',"RULE_S*","%Choice","RULE_S*",'")"']]},{name:"StringLiteral",bnf:[[`'"'`,/[^"]*/,`'"'`],[`"'"`,/[^']*/,`"'"`]]},{name:"CharCode",bnf:[['"#x"',/[0-9a-zA-Z]+/]]},{name:"CharClass",bnf:[["'['","'^'?","%RULE_CharClass_1+",'"]"']]},{name:"%RULE_CharClass_1",bnf:[["CharCodeRange"],["CharRange"],["CharCode"],["RULE_Char"]],fragment:!0},{name:"RULE_Char",bnf:[[/\x09/],[/\x0A/],[/\x0D/],[/[\x20-\x5c]/],[/[\x5e-\uD7FF]/],[/[\uE000-\uFFFD]/]]},{name:"CharRange",bnf:[["RULE_Char",'"-"',"RULE_Char"]]},{name:"CharCodeRange",bnf:[["CharCode",'"-"',"CharCode"]]},{name:"RULE_WHITESPACE",bnf:[["%RULE_WHITESPACE_CHAR*"],["Comment","RULE_WHITESPACE*"]]},{name:"RULE_S",bnf:[["RULE_WHITESPACE","RULE_S*"],["RULE_EOL","RULE_S*"]]},{name:"%RULE_WHITESPACE_CHAR",bnf:[[/\x09/],[/\x20/]],fragment:!0},{name:"Comment",bnf:[['"/*"',"%RULE_Comment_Body*",'"*/"']]},{name:"%RULE_Comment_Body",bnf:[[/[^*]/],['"*"+',/[^/]*/]],fragment:!0},{name:"RULE_EOL",bnf:[[/\x0D/,/\x0A/],[/\x0A/],[/\x0D/]]},{name:"Link",bnf:[["'['","Url","']'"]]},{name:"Url",bnf:[[/[^\x5D:/?#]/,'"://"',/[^\x5D#]+/,"%Url1?"]]},{name:"%Url1",bnf:[['"#"',"NCName"]],fragment:!0}],s.defaultParser=new kr.Parser(s.RULES,{debug:!1});let r=/^(!|&)/,l=/(\?|\+|\*)$/,c=/^%/;function d(D,$){if(typeof D=="string"){let U=l.exec(D),K=r.exec(D),te=K?K[0]:"",J=U?U[0]+" ":"";return c.test(D)?C(D,$)?te+m(D,$)+J:te+"("+m(D,$)+")"+J:D.replace(r,te)}else return D.source.replace(/\\(?:x|u)([a-zA-Z0-9]+)/g,"#x$1").replace(/\[\\(?:x|u)([a-zA-Z0-9]+)-\\(?:x|u)([a-zA-Z0-9]+)\]/g,"[#x$1-#x$2]")}function C(D,$){let U=kr.findRuleByName(D,$);return U&&U.bnf.length==1&&U.bnf[0].length==1&&(U.bnf[0][0]instanceof RegExp||U.bnf[0][0][0]=='"'||U.bnf[0][0][0]=="'")}function _(D,$){return D.map(U=>d(U,$)).join(" ")}function m(D,$){let U=kr.findRuleByName(D,$);return U?U.bnf.map(K=>_(K,$)).join(" | "):"RULE_NOT_FOUND {"+D+"}"}function A(D){let $=[];return D.grammarRules.forEach(U=>{if(!/^%/.test(U.name)){let K=U.recover?" { recoverUntil="+U.recover+" }":"";$.push(U.name+" ::= "+m(U.name,D)+K)}}),$.join(` +`)}s.emit=A;let P=0;function y(D,$){throw console.log("reberia restar "+$+" a "+D),new Error("Difference not supported yet")}function S(D){return new RegExp(D.replace(/#x([a-zA-Z0-9]{4})/g,"\\u$1").replace(/#x([a-zA-Z0-9]{3})/g,"\\u0$1").replace(/#x([a-zA-Z0-9]{2})/g,"\\x$1").replace(/#x([a-zA-Z0-9]{1})/g,"\\x0$1"))}function V(D,$,U,K){let te=null,J=[];return $.children.forEach((Q,G)=>{Q.type=="Minus"&&y(te,Q);let Ce=$.children[G+1];Ce=Ce&&Ce.type=="PrimaryDecoration"&&Ce.text||"";let Pe="";te&&te.type=="PrimaryPreDecoration"&&(Pe=te.text);let ot=Pe=="~"?1:void 0;switch(ot&&(Pe=""),Q.type){case"SubItem":let B="%"+(U+P++);M(D,Q,B,K),J.push(Pe+B+Ce);break;case"NCName":J.push(Pe+Q.text+Ce);break;case"StringLiteral":if(Ce||Pe||!/^['"/()a-zA-Z0-9&_.:=,+*\-\^\\]+$/.test(Q.text))J.push(Pe+Q.text+Ce);else for(let Oe of Q.text.slice(1,-1))K&&K.ignoreCase=="true"&&/[a-zA-Z]/.test(Oe)?J.push(new RegExp("["+Oe.toUpperCase()+Oe.toLowerCase()+"]")):J.push(new RegExp(kr.escapeRegExp(Oe)));break;case"CharCode":case"CharClass":if(Ce||Pe){let Oe={name:"%"+(U+P++),bnf:[[S(Q.text)]],pinned:ot};D.push(Oe),J.push(Pe+Oe.name+Ce)}else J.push(S(Q.text));break;case"PrimaryPreDecoration":case"PrimaryDecoration":break;default:throw new Error(" HOW SHOULD I PARSE THIS? "+Q.type+" -> "+JSON.stringify(Q.text))}te=Q}),J}function M(D,$,U,K=void 0){let te=$.children.filter(Ce=>Ce.type=="Attributes")[0],J={};te&&te.children.forEach(Ce=>{let Pe=Ce.children.filter(ot=>ot.type=="NCName")[0].text;if(Pe in J)throw new co.TokenError("Duplicated attribute "+Pe,Ce);J[Pe]=Ce.children.filter(ot=>ot.type=="AttributeValue")[0].text});let Q=$.children.filter(Ce=>Ce.type=="SequenceOrDifference").map(Ce=>V(D,Ce,U,K||J)),G={name:U,bnf:Q};if(U.indexOf("%")==0&&(G.fragment=!0),J.recoverUntil&&(G.recover=J.recoverUntil,G.bnf.length>1))throw new co.TokenError("only one-option productions are suitable for error recovering",$);if("pin"in J){let Ce=parseInt(J.pin);if(isNaN(Ce)||(G.pinned=Ce),G.bnf.length>1)throw new co.TokenError("only one-option productions are suitable for pinning",$)}"ws"in J?G.implicitWs=J.ws!="explicit":G.implicitWs=null,G.fragment=G.fragment||J.fragment=="true",G.simplifyWhenOneChildren=J.simplifyWhenOneChildren=="true",D.push(G)}function Y(D,$=s.defaultParser){let U=$.getAST(D);if(!U)throw new Error("Could not parse "+D);if(U.errors&&U.errors.length)throw U.errors[0];let K=null,te=U.children.filter(G=>G.type=="Attributes")[0],J={};te&&te.children.forEach(G=>{let Ce=G.children.filter(Pe=>Pe.type=="NCName")[0].text;if(Ce in J)throw new co.TokenError("Duplicated attribute "+Ce,G);J[Ce]=G.children.filter(Pe=>Pe.type=="AttributeValue")[0].text}),K=J.ws=="implicit";let Q=[];return U.children.filter(G=>G.type=="Production").map(G=>{let Ce=G.children.filter(Pe=>Pe.type=="NCName")[0].text;M(Q,G,Ce)}),Q.forEach(G=>{G.implicitWs===null&&(G.implicitWs=K)}),Q}s.getRules=Y;function se(D,$=s.defaultParser){return Y(D.join(""),$)}s.Transform=se;class ge extends kr.Parser{constructor($,U){let K=U&&U.debugRulesParser===!0?new kr.Parser(s.RULES,{debug:!0}):s.defaultParser;super(Y($,K),U)}emitSource(){return A(this)}}s.Parser=ge})(q3||(q3={}));H3.default=q3});var Vl=we(Si=>{"use strict";Object.defineProperty(Si,"__esModule",{value:!0});var J9=$l();Object.defineProperty(Si,"BNF",{enumerable:!0,get:function(){return J9.default}});var X9=Zl();Object.defineProperty(Si,"W3C",{enumerable:!0,get:function(){return X9.default}});var Q9=Gl();Object.defineProperty(Si,"Custom",{enumerable:!0,get:function(){return Q9.default}})});var Kl=we(Pi=>{"use strict";Object.defineProperty(Pi,"__esModule",{value:!0});var j9=Li();Object.defineProperty(Pi,"Parser",{enumerable:!0,get:function(){return j9.Parser}});var e7=oo();Object.defineProperty(Pi,"TokenError",{enumerable:!0,get:function(){return e7.TokenError}});Pi.Grammars=Vl()});var Ai=we(en=>{"use strict";Object.defineProperty(en,"__esModule",{value:!0});en.parseFormula=en.parseAndApply=en.Source=en.Formula=void 0;var Xe=Xt(),t7=Rl(),B3=$t(),n7=xl(),Yl=yl(),r7=Pl(),Jl=Il(),i7=x3(),o7=T3(),s7=Wl(),l7=Kl(),u7=Wr(),a7=` +tblfm_line ::= "" +formula_list ::= formula ( "::" formula_list )? +formula ::= destination "=" source display_directive? + +source ::= range | source_reference | single_param_function_call | conditional_function_call | algebraic_operation | float | real +range ::= source_reference ".." source_reference +source_reference ::= absolute_reference | relative_reference +destination ::= range | absolute_reference + +relative_reference ::= (relative_row | absolute_row) (relative_column | absolute_column) | relative_row | relative_column +relative_row ::= "@" ( "-" | "+" ) int +relative_column ::= "$" ( "-" | "+" ) int + +absolute_reference ::= absolute_row absolute_column | absolute_row | absolute_column +absolute_row ::= "@" ( "I" | "<" | ">" | int ) +absolute_column ::= "$" ( "<" | ">" | int ) + +single_param_function_call ::= single_param_function "(" source ")" +single_param_function ::= "mean" | "sum" + +conditional_function_call ::= "if(" predicate "," " "? source "," " "? source ")" +predicate ::= source_without_range conditional_operator source_without_range +source_without_range ::= source_reference | single_param_function_call | conditional_function_call | algebraic_operation | float | real +conditional_operator ::= ">" | "<" | ">=" | "<=" | "==" | "!=" + +algebraic_operation ::= "(" source " "? algebraic_operator " "? source ")" +algebraic_operator ::= "+" | "-" | "*" | "/" + +display_directive ::= ";" display_directive_option +display_directive_option ::= formatting_directive | datetime_directive | hourminute_directive +formatting_directive ::= "%." int "f" +datetime_directive ::= "dt" +hourminute_directive ::= "hm" + +float ::= "-"? int "." int +real ::= "-"? int +int ::= [0-9]+ +`,fo=class{constructor(r,l){this.merge=C=>this.destination.merge(this.source,C);let c=new Jl.DefaultFormatter;r.children.length===3&&(c=new Jl.DisplayDirective(r.children[2]));let d=(0,r7.newDestination)(r.children[0],l,c);if(d.isErr())throw d.error;this.destination=d.value,this.source=new ho(r.children[1],l)}};en.Formula=fo;var ho=class{constructor(r,l){if(this.getValue=(C,_)=>this.locationDescriptor.getValue(C,_),r.type!=="source"&&r.type!=="source_without_range")throw Error("Invalid AST token type of "+r.type);if(r.children.length!==1)throw Error("Unexpected children length in Source");let c=r.children[0],d=c7(c,l);if(d.isErr())throw d.error;this.locationDescriptor=d.value}};en.Source=ho;var c7=(s,r)=>{try{switch(s.type){case"range":return(0,Xe.ok)(new i7.Range(s,r));case"source_reference":let l=(0,B3.checkChildLength)(s,1);return l?(0,Xe.err)(l):(0,Xe.ok)(new o7.Reference(s.children[0],r));case"single_param_function_call":return(0,Xe.ok)(new s7.SingleParamFunctionCall(s,r));case"conditional_function_call":return(0,Xe.ok)(new n7.ConditionalFunctionCall(s,r));case"algebraic_operation":return(0,Xe.ok)(new t7.AlgebraicOperation(s,r));case"real":return(0,Xe.ok)(new Yl.Constant(s,r));case"float":return(0,Xe.ok)(new Yl.Constant(s,r));default:throw Error("Unrecognized valueProvider type "+s.type)}}catch(l){return(0,Xe.err)(l)}},f7=(s,r)=>s.reduce((c,d)=>c.andThen(C=>{let _=(0,en.parseFormula)(d,r);return _.isErr()?_:(0,Xe.ok)((0,u7.concat)(_.value,C))}),(0,Xe.ok)([])).andThen(c=>c.reduceRight((d,C)=>d.andThen(_=>C.merge(_)),(0,Xe.ok)(r)));en.parseAndApply=f7;var h7=(s,r)=>{let c=new l7.Grammars.W3C.Parser(a7).getAST(s);if(!c)return(0,Xe.err)(new Error(`Formula '${s}' could not be parsed`));let d=(0,B3.checkType)(c,"tblfm_line");if(d)return(0,Xe.err)(d);let C=(0,B3.checkChildLength)(c,1);if(C)return(0,Xe.err)(C);let _=c.children[0].children,m=[];try{do m.push(new fo(_[0],r)),_.length>1&&_[1].type==="formula_list"?_=_[1].children:_=[];while(_.length>0);return(0,Xe.ok)(m)}catch(A){return(0,Xe.err)(A)}};en.parseFormula=h7});var Ii=we(po=>{"use strict";Object.defineProperty(po,"__esModule",{value:!0});po.Table=void 0;var d7=Ai(),Xl=W1(),go=O1(),g7=P1(),z3=class s{constructor(r){this._rows=r.slice()}getHeight(){return this._rows.length}getWidth(){return this._rows.map(r=>r.getWidth()).reduce((r,l)=>Math.max(r,l),0)}getHeaderWidth(){return this._rows[0].getWidth()}getRows(){return this._rows.slice()}getDelimiterRow(){let r=this._rows[1];if(r!==void 0&&r.isDelimiter())return r}getCellAt(r,l){let c=this._rows[r];if(c!==void 0)return c.getCellAt(l)}getFocusedCell(r){return this.getCellAt(r.row,r.column)}toLines(){return this._rows.map(r=>r.toText())}setCellAt(r,l,c){let d=this.getRows();return d[r]=d[r].setCellAt(l,c),new s(d)}focusOfPosition(r,l){let c=r.row-l,d=this._rows[c];if(d===void 0)return;if(r.columnP.rawContent.length),_=d.marginLeft.length+1,m=0;for(;mr.column);m++)_+=C[m]+1;let A=r.column-_;return new Xl.Focus(c,m,A)}positionOfFocus(r,l){let c=this._rows[r.row];if(c===void 0)return;let d=r.row+l;if(r.column<0)return new go.Point(d,r.offset);let C=c.getCells().map(A=>A.rawContent.length),_=Math.min(r.column,C.length),m=c.marginLeft.length+1;for(let A=0;A<_;A++)m+=C[A]+1;return new go.Point(d,m+r.offset)}selectionRangeOfFocus(r,l){let c=this._rows[r.row];if(c===void 0)return;let d=c.getCellAt(r.column);if(d===void 0||d.content==="")return;let C=r.row+l,_=c.getCells().map(A=>A.rawContent.length),m=c.marginLeft.length+1;for(let A=0;A{"use strict";Object.defineProperty(rt,"__esModule",{value:!0});rt.readTable=rt._marginRegex=rt.marginRegexSrc=rt._readRow=rt._splitCells=void 0;var p7=Ii(),m7=Pr(),w7=_i(),C7=s=>{let r=[],l="",c=s;for(;c!=="";)switch(c[0]){case"`":{let d=c.match(/^`*/);if(d===null)break;let C=d[0],_=C,m=c.substr(C.length),A=!1;for(;m!=="";)if(m[0]==="`"){let P=m.match(/^`*/);if(P===null)break;let y=P[0];if(_+=y,m=m.substr(y.length),y.length===C.length){A=!0;break}}else _+=m[0],m=m.substr(1);A?(l+=_,c=m):(l+="`",c=c.substr(1))}break;case"\\":c.length>=2?(l+=c.substr(0,2),c=c.substr(2)):(l+="\\",c=c.substr(1));break;case"[":if(l+="[",c=c.substr(1),/\[[^\\|\]]+\|[^|\]]+]]/.test(c)){let d=c.indexOf("|");l+=c.slice(0,d),l+="\\|",c=c.substr(d+1)}break;case"|":r.push(l),l="",c=c.substr(1);break;default:l+=c[0],c=c.substr(1)}return r.push(l),r};rt._splitCells=C7;var v7=(s,r=/^\s*$/)=>{let l=(0,rt._splitCells)(s),c;l.length>0&&r.test(l[0])?(c=l[0],l=l.slice(1)):c="";let d;return l.length>1&&/^\s*$/.test(l[l.length-1])?(d=l[l.length-1],l=l.slice(0,l.length-1)):d="",new w7.TableRow(l.map(C=>new m7.TableCell(C)),c,d)};rt._readRow=v7;var _7=s=>{let r="";return s.forEach(l=>{l!=="|"&&l!=="\\"&&l!=="`"&&(r+=`\\u{${l.codePointAt(0).toString(16)}}`)}),`[\\s${r}]*`};rt.marginRegexSrc=_7;var b7=s=>new RegExp(`^${(0,rt.marginRegexSrc)(s)}$`,"u");rt._marginRegex=b7;var E7=(s,r)=>{let l=(0,rt._marginRegex)(r.leftMarginChars);return new p7.Table(s.map(c=>(0,rt._readRow)(c,l)))};rt.readTable=E7});var jl=we(Wi=>{"use strict";Object.defineProperty(Wi,"__esModule",{value:!0});var Z3=[[0,31,"N"],[32,126,"Na"],[127,160,"N"],[161,161,"A"],[162,163,"Na"],[164,164,"A"],[165,166,"Na"],[167,168,"A"],[169,169,"N"],[170,170,"A"],[171,171,"N"],[172,172,"Na"],[173,174,"A"],[175,175,"Na"],[176,180,"A"],[181,181,"N"],[182,186,"A"],[187,187,"N"],[188,191,"A"],[192,197,"N"],[198,198,"A"],[199,207,"N"],[208,208,"A"],[209,214,"N"],[215,216,"A"],[217,221,"N"],[222,225,"A"],[226,229,"N"],[230,230,"A"],[231,231,"N"],[232,234,"A"],[235,235,"N"],[236,237,"A"],[238,239,"N"],[240,240,"A"],[241,241,"N"],[242,243,"A"],[244,246,"N"],[247,250,"A"],[251,251,"N"],[252,252,"A"],[253,253,"N"],[254,254,"A"],[255,256,"N"],[257,257,"A"],[258,272,"N"],[273,273,"A"],[274,274,"N"],[275,275,"A"],[276,282,"N"],[283,283,"A"],[284,293,"N"],[294,295,"A"],[296,298,"N"],[299,299,"A"],[300,304,"N"],[305,307,"A"],[308,311,"N"],[312,312,"A"],[313,318,"N"],[319,322,"A"],[323,323,"N"],[324,324,"A"],[325,327,"N"],[328,331,"A"],[332,332,"N"],[333,333,"A"],[334,337,"N"],[338,339,"A"],[340,357,"N"],[358,359,"A"],[360,362,"N"],[363,363,"A"],[364,461,"N"],[462,462,"A"],[463,463,"N"],[464,464,"A"],[465,465,"N"],[466,466,"A"],[467,467,"N"],[468,468,"A"],[469,469,"N"],[470,470,"A"],[471,471,"N"],[472,472,"A"],[473,473,"N"],[474,474,"A"],[475,475,"N"],[476,476,"A"],[477,592,"N"],[593,593,"A"],[594,608,"N"],[609,609,"A"],[610,707,"N"],[708,708,"A"],[709,710,"N"],[711,711,"A"],[712,712,"N"],[713,715,"A"],[716,716,"N"],[717,717,"A"],[718,719,"N"],[720,720,"A"],[721,727,"N"],[728,731,"A"],[732,732,"N"],[733,733,"A"],[734,734,"N"],[735,735,"A"],[736,767,"N"],[768,879,"A"],[880,912,"N"],[913,929,"A"],[930,930,"N"],[931,937,"A"],[938,944,"N"],[945,961,"A"],[962,962,"N"],[963,969,"A"],[970,1024,"N"],[1025,1025,"A"],[1026,1039,"N"],[1040,1103,"A"],[1104,1104,"N"],[1105,1105,"A"],[1106,4351,"N"],[4352,4447,"W"],[4448,8207,"N"],[8208,8208,"A"],[8209,8210,"N"],[8211,8214,"A"],[8215,8215,"N"],[8216,8217,"A"],[8218,8219,"N"],[8220,8221,"A"],[8222,8223,"N"],[8224,8226,"A"],[8227,8227,"N"],[8228,8231,"A"],[8232,8239,"N"],[8240,8240,"A"],[8241,8241,"N"],[8242,8243,"A"],[8244,8244,"N"],[8245,8245,"A"],[8246,8250,"N"],[8251,8251,"A"],[8252,8253,"N"],[8254,8254,"A"],[8255,8307,"N"],[8308,8308,"A"],[8309,8318,"N"],[8319,8319,"A"],[8320,8320,"N"],[8321,8324,"A"],[8325,8360,"N"],[8361,8361,"H"],[8362,8363,"N"],[8364,8364,"A"],[8365,8450,"N"],[8451,8451,"A"],[8452,8452,"N"],[8453,8453,"A"],[8454,8456,"N"],[8457,8457,"A"],[8458,8466,"N"],[8467,8467,"A"],[8468,8469,"N"],[8470,8470,"A"],[8471,8480,"N"],[8481,8482,"A"],[8483,8485,"N"],[8486,8486,"A"],[8487,8490,"N"],[8491,8491,"A"],[8492,8530,"N"],[8531,8532,"A"],[8533,8538,"N"],[8539,8542,"A"],[8543,8543,"N"],[8544,8555,"A"],[8556,8559,"N"],[8560,8569,"A"],[8570,8584,"N"],[8585,8585,"A"],[8586,8591,"N"],[8592,8601,"A"],[8602,8631,"N"],[8632,8633,"A"],[8634,8657,"N"],[8658,8658,"A"],[8659,8659,"N"],[8660,8660,"A"],[8661,8678,"N"],[8679,8679,"A"],[8680,8703,"N"],[8704,8704,"A"],[8705,8705,"N"],[8706,8707,"A"],[8708,8710,"N"],[8711,8712,"A"],[8713,8714,"N"],[8715,8715,"A"],[8716,8718,"N"],[8719,8719,"A"],[8720,8720,"N"],[8721,8721,"A"],[8722,8724,"N"],[8725,8725,"A"],[8726,8729,"N"],[8730,8730,"A"],[8731,8732,"N"],[8733,8736,"A"],[8737,8738,"N"],[8739,8739,"A"],[8740,8740,"N"],[8741,8741,"A"],[8742,8742,"N"],[8743,8748,"A"],[8749,8749,"N"],[8750,8750,"A"],[8751,8755,"N"],[8756,8759,"A"],[8760,8763,"N"],[8764,8765,"A"],[8766,8775,"N"],[8776,8776,"A"],[8777,8779,"N"],[8780,8780,"A"],[8781,8785,"N"],[8786,8786,"A"],[8787,8799,"N"],[8800,8801,"A"],[8802,8803,"N"],[8804,8807,"A"],[8808,8809,"N"],[8810,8811,"A"],[8812,8813,"N"],[8814,8815,"A"],[8816,8833,"N"],[8834,8835,"A"],[8836,8837,"N"],[8838,8839,"A"],[8840,8852,"N"],[8853,8853,"A"],[8854,8856,"N"],[8857,8857,"A"],[8858,8868,"N"],[8869,8869,"A"],[8870,8894,"N"],[8895,8895,"A"],[8896,8977,"N"],[8978,8978,"A"],[8979,8985,"N"],[8986,8987,"W"],[8988,9e3,"N"],[9001,9002,"W"],[9003,9192,"N"],[9193,9196,"W"],[9197,9199,"N"],[9200,9200,"W"],[9201,9202,"N"],[9203,9203,"W"],[9204,9311,"N"],[9312,9449,"A"],[9450,9450,"N"],[9451,9547,"A"],[9548,9551,"N"],[9552,9587,"A"],[9588,9599,"N"],[9600,9615,"A"],[9616,9617,"N"],[9618,9621,"A"],[9622,9631,"N"],[9632,9633,"A"],[9634,9634,"N"],[9635,9641,"A"],[9642,9649,"N"],[9650,9651,"A"],[9652,9653,"N"],[9654,9655,"A"],[9656,9659,"N"],[9660,9661,"A"],[9662,9663,"N"],[9664,9665,"A"],[9666,9669,"N"],[9670,9672,"A"],[9673,9674,"N"],[9675,9675,"A"],[9676,9677,"N"],[9678,9681,"A"],[9682,9697,"N"],[9698,9701,"A"],[9702,9710,"N"],[9711,9711,"A"],[9712,9724,"N"],[9725,9726,"W"],[9727,9732,"N"],[9733,9734,"A"],[9735,9736,"N"],[9737,9737,"A"],[9738,9741,"N"],[9742,9743,"A"],[9744,9747,"N"],[9748,9749,"W"],[9750,9755,"N"],[9756,9756,"A"],[9757,9757,"N"],[9758,9758,"A"],[9759,9791,"N"],[9792,9792,"A"],[9793,9793,"N"],[9794,9794,"A"],[9795,9799,"N"],[9800,9811,"W"],[9812,9823,"N"],[9824,9825,"A"],[9826,9826,"N"],[9827,9829,"A"],[9830,9830,"N"],[9831,9834,"A"],[9835,9835,"N"],[9836,9837,"A"],[9838,9838,"N"],[9839,9839,"A"],[9840,9854,"N"],[9855,9855,"W"],[9856,9874,"N"],[9875,9875,"W"],[9876,9885,"N"],[9886,9887,"A"],[9888,9888,"N"],[9889,9889,"W"],[9890,9897,"N"],[9898,9899,"W"],[9900,9916,"N"],[9917,9918,"W"],[9919,9919,"A"],[9920,9923,"N"],[9924,9925,"W"],[9926,9933,"A"],[9934,9934,"W"],[9935,9939,"A"],[9940,9940,"W"],[9941,9953,"A"],[9954,9954,"N"],[9955,9955,"A"],[9956,9959,"N"],[9960,9961,"A"],[9962,9962,"W"],[9963,9969,"A"],[9970,9971,"W"],[9972,9972,"A"],[9973,9973,"W"],[9974,9977,"A"],[9978,9978,"W"],[9979,9980,"A"],[9981,9981,"W"],[9982,9983,"A"],[9984,9988,"N"],[9989,9989,"W"],[9990,9993,"N"],[9994,9995,"W"],[9996,10023,"N"],[10024,10024,"W"],[10025,10044,"N"],[10045,10045,"A"],[10046,10059,"N"],[10060,10060,"W"],[10061,10061,"N"],[10062,10062,"W"],[10063,10066,"N"],[10067,10069,"W"],[10070,10070,"N"],[10071,10071,"W"],[10072,10101,"N"],[10102,10111,"A"],[10112,10132,"N"],[10133,10135,"W"],[10136,10159,"N"],[10160,10160,"W"],[10161,10174,"N"],[10175,10175,"W"],[10176,10213,"N"],[10214,10221,"Na"],[10222,10628,"N"],[10629,10630,"Na"],[10631,11034,"N"],[11035,11036,"W"],[11037,11087,"N"],[11088,11088,"W"],[11089,11092,"N"],[11093,11093,"W"],[11094,11097,"A"],[11098,11903,"N"],[11904,11929,"W"],[11930,11930,"N"],[11931,12019,"W"],[12020,12031,"N"],[12032,12245,"W"],[12246,12271,"N"],[12272,12283,"W"],[12284,12287,"N"],[12288,12288,"F"],[12289,12350,"W"],[12351,12352,"N"],[12353,12438,"W"],[12439,12440,"N"],[12441,12543,"W"],[12544,12548,"N"],[12549,12591,"W"],[12592,12592,"N"],[12593,12686,"W"],[12687,12687,"N"],[12688,12771,"W"],[12772,12783,"N"],[12784,12830,"W"],[12831,12831,"N"],[12832,12871,"W"],[12872,12879,"A"],[12880,19903,"W"],[19904,19967,"N"],[19968,42124,"W"],[42125,42127,"N"],[42128,42182,"W"],[42183,43359,"N"],[43360,43388,"W"],[43389,44031,"N"],[44032,55203,"W"],[55204,57343,"N"],[57344,63743,"A"],[63744,64255,"W"],[64256,65023,"N"],[65024,65039,"A"],[65040,65049,"W"],[65050,65071,"N"],[65072,65106,"W"],[65107,65107,"N"],[65108,65126,"W"],[65127,65127,"N"],[65128,65131,"W"],[65132,65280,"N"],[65281,65376,"F"],[65377,65470,"H"],[65471,65473,"N"],[65474,65479,"H"],[65480,65481,"N"],[65482,65487,"H"],[65488,65489,"N"],[65490,65495,"H"],[65496,65497,"N"],[65498,65500,"H"],[65501,65503,"N"],[65504,65510,"F"],[65511,65511,"N"],[65512,65518,"H"],[65519,65532,"N"],[65533,65533,"A"],[65534,94175,"N"],[94176,94180,"W"],[94181,94191,"N"],[94192,94193,"W"],[94194,94207,"N"],[94208,100343,"W"],[100344,100351,"N"],[100352,101589,"W"],[101590,101631,"N"],[101632,101640,"W"],[101641,110591,"N"],[110592,110878,"W"],[110879,110927,"N"],[110928,110930,"W"],[110931,110947,"N"],[110948,110951,"W"],[110952,110959,"N"],[110960,111355,"W"],[111356,126979,"N"],[126980,126980,"W"],[126981,127182,"N"],[127183,127183,"W"],[127184,127231,"N"],[127232,127242,"A"],[127243,127247,"N"],[127248,127277,"A"],[127278,127279,"N"],[127280,127337,"A"],[127338,127343,"N"],[127344,127373,"A"],[127374,127374,"W"],[127375,127376,"A"],[127377,127386,"W"],[127387,127404,"A"],[127405,127487,"N"],[127488,127490,"W"],[127491,127503,"N"],[127504,127547,"W"],[127548,127551,"N"],[127552,127560,"W"],[127561,127567,"N"],[127568,127569,"W"],[127570,127583,"N"],[127584,127589,"W"],[127590,127743,"N"],[127744,127776,"W"],[127777,127788,"N"],[127789,127797,"W"],[127798,127798,"N"],[127799,127868,"W"],[127869,127869,"N"],[127870,127891,"W"],[127892,127903,"N"],[127904,127946,"W"],[127947,127950,"N"],[127951,127955,"W"],[127956,127967,"N"],[127968,127984,"W"],[127985,127987,"N"],[127988,127988,"W"],[127989,127991,"N"],[127992,128062,"W"],[128063,128063,"N"],[128064,128064,"W"],[128065,128065,"N"],[128066,128252,"W"],[128253,128254,"N"],[128255,128317,"W"],[128318,128330,"N"],[128331,128334,"W"],[128335,128335,"N"],[128336,128359,"W"],[128360,128377,"N"],[128378,128378,"W"],[128379,128404,"N"],[128405,128406,"W"],[128407,128419,"N"],[128420,128420,"W"],[128421,128506,"N"],[128507,128591,"W"],[128592,128639,"N"],[128640,128709,"W"],[128710,128715,"N"],[128716,128716,"W"],[128717,128719,"N"],[128720,128722,"W"],[128723,128724,"N"],[128725,128727,"W"],[128728,128746,"N"],[128747,128748,"W"],[128749,128755,"N"],[128756,128764,"W"],[128765,128991,"N"],[128992,129003,"W"],[129004,129291,"N"],[129292,129338,"W"],[129339,129339,"N"],[129340,129349,"W"],[129350,129350,"N"],[129351,129400,"W"],[129401,129401,"N"],[129402,129483,"W"],[129484,129484,"N"],[129485,129535,"W"],[129536,129647,"N"],[129648,129652,"W"],[129653,129655,"N"],[129656,129658,"W"],[129659,129663,"N"],[129664,129670,"W"],[129671,129679,"N"],[129680,129704,"W"],[129705,129711,"N"],[129712,129718,"W"],[129719,129727,"N"],[129728,129730,"W"],[129731,129743,"N"],[129744,129750,"W"],[129751,131071,"N"],[131072,196605,"W"],[196606,196607,"N"],[196608,262141,"W"],[262142,917759,"N"],[917760,917999,"A"],[918e3,983039,"N"],[983040,1048573,"A"],[1048574,1048575,"N"],[1048576,1114109,"A"],[1114110,1114111,"N"]],A7="13.0.0";function T7(s){for(var r=0,l=Z3.length-1;r!==l;){var c=r+(l-r>>1),d=Z3[c],C=d[0],_=d[1],m=d[2];if(s_)r=c+1;else return m}return Z3[r][2]}function Ql(s,r){r===void 0&&(r=0);var l=s.codePointAt(r);if(l!==void 0)return T7(l)}var R7={N:1,Na:1,W:2,F:2,H:1,A:1};function x7(s,r){for(var l=0,c=0,d=s;c{"use strict";Object.defineProperty(oe,"__esModule",{value:!0});oe.moveColumn=oe.deleteColumn=oe.insertColumn=oe.moveRow=oe.deleteRow=oe.insertRow=oe.alterAlignment=oe.formatTable=oe.FormatType=oe._weakFormatTable=oe._formatTable=oe._padText=oe._alignText=oe._computeTextWidth=oe.completeTable=oe._extendArray=oe._delimiterText=void 0;var ft=vi(),Gt=Ii(),Ct=Pr(),Qe=_i(),y7=jl(),N7=(s,r)=>{let l="-".repeat(r);switch(s){case ft.Alignment.NONE:return` ${l} `;case ft.Alignment.LEFT:return`:${l} `;case ft.Alignment.RIGHT:return` ${l}:`;case ft.Alignment.CENTER:return`:${l}:`;default:throw new Error("Unknown alignment: "+s)}};oe._delimiterText=N7;var L7=(s,r,l)=>{let c=s.slice();for(let d=s.length;d{let l=s.getHeight(),c=s.getWidth();if(l===0)throw new Error("Empty table");let d=s.getRows(),C=[],_=d[0],m=_.getCells();C.push(new Qe.TableRow((0,oe._extendArray)(m,c,P=>new Ct.TableCell(P===m.length?_.marginRight:"")),_.marginLeft,m.lengthnew Ct.TableCell((0,oe._delimiterText)(ft.Alignment.NONE,y===P.length?Math.max(r.minDelimiterWidth,A.marginRight.length-2):r.minDelimiterWidth))),A.marginLeft,P.lengthnew Ct.TableCell((0,oe._delimiterText)(ft.Alignment.NONE,r.minDelimiterWidth))),"",""));for(let P=A!==void 0?2:1;Pnew Ct.TableCell(V===S.length?y.marginRight:"")),y.marginLeft,S.length{let l=r.normalize?s.normalize("NFC"):s,c=0;for(let d of l){if(r.wideChars.has(d)){c+=2;continue}if(r.narrowChars.has(d)){c+=1;continue}switch((0,y7.getEAW)(d)){case"F":case"W":c+=2;break;case"A":c+=r.ambiguousAsWide?2:1;break;default:c+=1}}return c};oe._computeTextWidth=S7;var P7=(s,r,l,c)=>{let d=r-(0,oe._computeTextWidth)(s,c);if(d<0)return s;switch(l){case ft.Alignment.NONE:throw new Error("Unexpected default alignment");case ft.Alignment.LEFT:return s+" ".repeat(d);case ft.Alignment.RIGHT:return" ".repeat(d)+s;case ft.Alignment.CENTER:return" ".repeat(Math.floor(d/2))+s+" ".repeat(Math.ceil(d/2));default:throw new Error("Unknown alignment: "+l)}};oe._alignText=P7;var I7=s=>` ${s} `;oe._padText=I7;var W7=(s,r)=>{let l=s.getHeight(),c=s.getWidth();if(l===0)return{table:s,marginLeft:""};let d=s.getRows()[0].marginLeft;if(c===0){let y=new Array(l).fill(new Qe.TableRow([],d,""));return{table:new Gt.Table(y),marginLeft:d}}let C=s.getDelimiterRow(),_=new Array(c).fill(0);if(C!==void 0){let y=C.getWidth();for(let S=0;Sy.getAlignment()),c,()=>r.defaultAlignment):new Array(c).fill(r.defaultAlignment),A=[],P=s.getRows()[0];A.push(new Qe.TableRow(P.getCells().map((y,S)=>new Ct.TableCell((0,oe._padText)((0,oe._alignText)(y.content,_[S],r.headerAlignment===ft.HeaderAlignment.FOLLOW?m[S]===ft.Alignment.NONE?r.defaultAlignment:m[S]:r.headerAlignment,r.textWidthOptions)))),d,"")),C!==void 0&&A.push(new Qe.TableRow(C.getCells().map((y,S)=>new Ct.TableCell((0,oe._delimiterText)(m[S],_[S]))),d,""));for(let y=C!==void 0?2:1;ynew Ct.TableCell((0,oe._padText)((0,oe._alignText)(V.content,_[M],m[M]===ft.Alignment.NONE?r.defaultAlignment:m[M],r.textWidthOptions)))),d,""))}return{table:new Gt.Table(A),marginLeft:d}};oe._formatTable=W7;var M7=(s,r)=>{let l=s.getHeight(),c=s.getWidth();if(l===0)return{table:s,marginLeft:""};let d=s.getRows()[0].marginLeft;if(c===0){let A=new Array(l).fill(new Qe.TableRow([],d,""));return{table:new Gt.Table(A),marginLeft:d}}let C=s.getDelimiterRow(),_=[],m=s.getRows()[0];_.push(new Qe.TableRow(m.getCells().map(A=>new Ct.TableCell((0,oe._padText)(A.content))),d,"")),C!==void 0&&_.push(new Qe.TableRow(C.getCells().map(A=>new Ct.TableCell((0,oe._delimiterText)(A.getAlignment(),r.minDelimiterWidth))),d,""));for(let A=C!==void 0?2:1;Anew Ct.TableCell((0,oe._padText)(y.content))),d,""))}return{table:new Gt.Table(_),marginLeft:d}};oe._weakFormatTable=M7;var mo;(function(s){s.NORMAL="normal",s.WEAK="weak"})(mo||(oe.FormatType=mo={}));var D7=(s,r)=>{switch(r.formatType){case mo.NORMAL:return(0,oe._formatTable)(s,r);case mo.WEAK:return(0,oe._weakFormatTable)(s,r);default:throw new Error("Unknown format type: "+r.formatType)}};oe.formatTable=D7;var F7=(s,r,l,c)=>{if(s.getHeight()<1)return s;let d=s.getRows()[1];if(r<0||d.getWidth()-1{let c=s.getRows();return c.splice(Math.max(r,2),0,l),new Gt.Table(c)};oe.insertRow=k7;var U7=(s,r)=>{if(r===1)return s;let l=s.getRows();if(r===0){let c=l[0];l[0]=new Qe.TableRow(new Array(c.getWidth()).fill(new Ct.TableCell("")),c.marginLeft,c.marginRight)}else l.splice(r,1);return new Gt.Table(l)};oe.deleteRow=U7;var q7=(s,r,l)=>{if(r<=1||l<=1||r===l)return s;let c=s.getRows(),d=c[r];return c.splice(r,1),c.splice(l,0,d),new Gt.Table(c)};oe.moveRow=q7;var H7=(s,r,l,c)=>{let d=s.getRows();for(let C=0;C1?C-1:C];m.splice(r,0,A),d[C]=new Qe.TableRow(m,_.marginLeft,_.marginRight)}return new Gt.Table(d)};oe.insertColumn=H7;var B7=(s,r,l)=>{let c=s.getRows();for(let d=0;d{if(r===l)return s;let c=s.getRows();for(let d=0;d{"use strict";Object.defineProperty(Wt,"__esModule",{value:!0});Wt.shortestEditScript=Wt.applyEditScript=Wt._applyCommand=Wt.Delete=Wt.Insert=void 0;var Ur=class{constructor(r,l){this.row=r,this.line=l}};Wt.Insert=Ur;var qr=class{constructor(r){this.row=r}};Wt.Delete=qr;var $7=(s,r,l)=>{if(r instanceof Ur)s.insertLine(l+r.row,r.line);else if(r instanceof qr)s.deleteLine(l+r.row);else throw new Error("Unknown command")};Wt._applyCommand=$7;var Z7=(s,r,l)=>{for(let c of r)(0,Wt._applyCommand)(s,c,l)};Wt.applyEditScript=Z7;var Co=class{get car(){throw new Error("Not implemented")}get cdr(){throw new Error("Not implemented")}isEmpty(){throw new Error("Not implemented")}unshift(r){return new V3(r,this)}toArray(){let r=[],l=this;for(;!l.isEmpty();)r.push(l.car),l=l.cdr;return r}},G3=class extends Co{constructor(){super()}get car(){throw new Error("Empty list")}get cdr(){throw new Error("Empty list")}isEmpty(){return!0}},V3=class extends Co{constructor(r,l){super(),this._car=r,this._cdr=l}get car(){return this._car}get cdr(){return this._cdr}isEmpty(){return!1}},G7=(s,r,l=-1)=>{let c=s.length,d=r.length,C=l>=0?Math.min(l,c+d):c+d,_=new Array(Math.min(C,c)+Math.min(C,d)+1),m=Math.min(C,c);for(let A=0;A<=C;A++){let P=A<=c?-A:A-2*c,y=A<=d?A:-A+2*d;for(let S=P;S<=y;S+=2){let V,M;if(A===0)V=0,M=new G3;else if(S===-A)V=_[m+S+1].i+1,M=_[m+S+1].script.unshift(new qr(V+S));else if(S===A)V=_[m+S-1].i,M=_[m+S-1].script.unshift(new Ur(V+S-1,r[V+S-1]));else{let Y=_[m+S+1].i+1,se=_[m+S-1].i;Y>se?(V=Y,M=_[m+S+1].script.unshift(new qr(V+S))):(V=se,M=_[m+S-1].script.unshift(new Ur(V+S-1,r[V+S-1])))}for(;V{"use strict";Object.defineProperty(vo,"__esModule",{value:!0});vo.ITextEditor=void 0;var Y3=class{getCursorPosition(){throw new Error("Not implemented: getCursorPosition")}setCursorPosition(r){throw new Error("Not implemented: setCursorPosition")}setSelectionRange(r){throw new Error("Not implemented: setSelectionRange")}getLastRow(){throw new Error("Not implemented: getLastRow")}acceptsTableEdit(r){throw new Error("Not implemented: acceptsTableEdit")}getLine(r){throw new Error("Not implemented: getLine")}insertLine(r,l){throw new Error("Not implemented: insertLine")}deleteLine(r){throw new Error("Not implemented: deleteLine")}replaceLines(r,l,c){throw new Error("Not implemented: replaceLines")}transact(r){throw new Error("Not implemented: transact")}};vo.ITextEditor=Y3});var ru=we(dr=>{"use strict";Object.defineProperty(dr,"__esModule",{value:!0});dr.defaultOptions=dr.optionsWithDefaults=void 0;var tu=vi(),V7=wo(),nu={normalize:!0,wideChars:new Set,narrowChars:new Set,ambiguousAsWide:!1},K7={leftMarginChars:new Set,formatType:V7.FormatType.NORMAL,minDelimiterWidth:3,defaultAlignment:tu.DefaultAlignment.LEFT,headerAlignment:tu.HeaderAlignment.FOLLOW,smartCursor:!1},Y7=s=>Object.assign(Object.assign(Object.assign({},K7),s),{textWidthOptions:s.textWidthOptions?Object.assign(Object.assign({},nu),s.textWidthOptions):nu});dr.optionsWithDefaults=Y7;dr.defaultOptions=(0,dr.optionsWithDefaults)({})});var su=we(We=>{"use strict";Object.defineProperty(We,"__esModule",{value:!0});We.TableEditor=We._computeNewOffset=We._createIsTableFormulaRegex=We._createIsTableRowRegex=We.SortOrder=void 0;var iu=K3(),_o=W1(),Le=wo(),Br=$3(),ln=O1(),J3=P1(),ou=Ii(),un=Pr(),Hr=_i(),X3;(function(s){s.Ascending="ascending",s.Descending="descending"})(X3||(We.SortOrder=X3={}));var J7=s=>new RegExp(`^${(0,Br.marginRegexSrc)(s)}\\|`,"u");We._createIsTableRowRegex=J7;var X7=s=>new RegExp(`^${(0,Br.marginRegexSrc)(s)}$`,"u");We._createIsTableFormulaRegex=X7;var Q7=(s,r,l,c)=>{if(c){let _=l.table.getFocusedCell(s);return _!==void 0?_.computeRawOffset(0):s.column<0?l.marginLeft.length:0}let d=r.getFocusedCell(s),C=l.table.getFocusedCell(s);if(d!==void 0&&C!==void 0){let _=Math.min(d.computeContentOffset(s.offset),C.content.length);return C.computeRawOffset(_)}return s.column<0?l.marginLeft.length:0};We._computeNewOffset=Q7;var Q3=class{constructor(r){this._textEditor=r,this._scActive=!1}resetSmartCursor(){this._scActive=!1}cursorIsInTable(r){let l=(0,We._createIsTableRowRegex)(r.leftMarginChars),c=this._textEditor.getCursorPosition();return this._textEditor.acceptsTableEdit(c.row)&&l.test(this._textEditor.getLine(c.row))}cursorIsInTableFormula(r){let l=(0,We._createIsTableFormulaRegex)(r.leftMarginChars),c=this._textEditor.getCursorPosition();return this._textEditor.acceptsTableEdit(c.row)&&l.test(this._textEditor.getLine(c.row))}_findTable(r){let l=(0,We._createIsTableRowRegex)(r.leftMarginChars),c=(0,We._createIsTableFormulaRegex)(r.leftMarginChars),d=this._textEditor.getCursorPosition(),C=this._textEditor.getLastRow(),_=[],m=[],A=d.row,P=d.row;{let M=this._textEditor.getLine(d.row);for(;c.test(M)&&d.row>=0;)d=new ln.Point(d.row-1,d.column),P--,M=this._textEditor.getLine(d.row)}{let M=this._textEditor.getLine(d.row);if(!this._textEditor.acceptsTableEdit(d.row)||!l.test(M))return;_.push(M)}for(let M=d.row-1;M>=0;M--){let Y=this._textEditor.getLine(M);if(!this._textEditor.acceptsTableEdit(M)||!l.test(Y))break;_.unshift(Y),A=M}for(let M=d.row+1;M<=C;M++){let Y=this._textEditor.getLine(M);if(!this._textEditor.acceptsTableEdit(M)||!l.test(Y))break;_.push(Y),P=M}for(let M=P+1;M<=C;M++){let Y=this._textEditor.getLine(M);if(!this._textEditor.acceptsTableEdit(M)||!c.test(Y))break;m.push(Y)}let y=new J3.Range(new ln.Point(A,0),new ln.Point(P,_[_.length-1].length)),S=(0,Br.readTable)(_,r),V=S.focusOfPosition(d,A);if(V!==void 0)return{range:y,lines:_,formulaLines:m,table:S,focus:V}}_withTable(r,l){let c=this._findTable(r);if(c!==void 0)return l(c)}_updateLines(r,l,c,d=void 0){if(d!==void 0){let C=(0,iu.shortestEditScript)(d,c,3);if(C!==void 0){(0,iu.applyEditScript)(this._textEditor,C,r);return}}this._textEditor.replaceLines(r,l,c)}_moveToFocus(r,l,c){let d=l.positionOfFocus(c,r);d!==void 0&&this._textEditor.setCursorPosition(d)}_selectFocus(r,l,c){let d=l.selectionRangeOfFocus(c,r);d!==void 0?this._textEditor.setSelectionRange(d):this._moveToFocus(r,l,c)}format(r){this.withCompletedTable(r,({range:l,lines:c,table:d,focus:C})=>{let _=C;this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,d.toLines(),c),this._moveToFocus(l.start.row,d,_)})})}escape(r){this._withTable(r,({range:l,lines:c,table:d,focus:C})=>{let _=(0,Le.completeTable)(d,r),m=(0,Le.formatTable)(_.table,r),A=l.end.row+(_.delimiterInserted?2:1);this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,m.table.toLines(),c);let P;if(A>this._textEditor.getLastRow())this._textEditor.insertLine(A,""),P=new ln.Point(A,0);else{let y=new RegExp(`^${(0,Br.marginRegexSrc)(r.leftMarginChars)}`,"u"),S=this._textEditor.getLine(A),V=y.exec(S)[0];P=new ln.Point(A,V.length)}this._textEditor.setCursorPosition(P)}),this.resetSmartCursor()})}alignColumn(r,l){this.withCompletedTable(l,({range:c,lines:d,table:C,focus:_})=>{let m=_,A=C;0<=m.column&&m.column<=A.getHeaderWidth()-1&&(A=(0,Le.alterAlignment)(C,m.column,r,l));let P=(0,Le.formatTable)(A,l);m=m.setOffset((0,We._computeNewOffset)(m,C,P,!1)),this._textEditor.transact(()=>{this._updateLines(c.start.row,c.end.row+1,P.table.toLines(),d),this._moveToFocus(c.start.row,P.table,m)})})}selectCell(r){this.withCompletedTable(r,({range:l,lines:c,table:d,focus:C})=>{let _=C;this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,d.toLines(),c),this._selectFocus(l.start.row,d,_)})})}moveFocus(r,l,c){this.withCompletedTable(c,({range:d,lines:C,table:_,focus:m})=>{let A=m,P=A;if(r!==0){let V=_.getHeight(),M=A.row<1&&A.row+r>=1?1:A.row>1&&A.row+r<=1?-1:0;A=A.setRow(Math.min(Math.max(A.row+r+M,0),V<=2?0:V-1))}if(l!==0){let V=_.getHeaderWidth();!(A.column<0&&l<0)&&!(A.column>V-1&&l>0)&&(A=A.setColumn(Math.min(Math.max(A.column+l,0),V-1)))}let y=!A.posEquals(P),S=(0,Le.formatTable)(_,c);A=A.setOffset((0,We._computeNewOffset)(A,_,S,y)),this._textEditor.transact(()=>{this._updateLines(d.start.row,d.end.row+1,S.table.toLines(),C),y?this._selectFocus(d.start.row,S.table,A):this._moveToFocus(d.start.row,S.table,A)}),y&&this.resetSmartCursor()})}nextCell(r){this._withTable(r,({range:l,lines:c,table:d,focus:C})=>{let _=this._scTablePos!==void 0&&!l.start.equals(this._scTablePos)||this._scLastFocus!==void 0&&!C.posEquals(this._scLastFocus);this._scActive&&_&&this.resetSmartCursor();let m=C,A=(0,Le.completeTable)(d,r);A.delimiterInserted&&m.row>0&&(m=m.setRow(m.row+1));let P=m,y=A.table;if(m.row===1){if(m=m.setRow(2),r.smartCursor?(m.column<0||y.getHeaderWidth()-1y.getHeight()-1){let M=new Array(y.getHeaderWidth()).fill(new un.TableCell(""));y=(0,Le.insertRow)(y,y.getHeight(),new Hr.TableRow(M,"",""))}}else{if(m.column>y.getHeaderWidth()-1){let M=new Array(y.getHeight()-1).fill(new un.TableCell(""));y=(0,Le.insertColumn)(y,y.getHeaderWidth(),M,r)}m=m.setColumn(m.column+1)}let S=(0,Le.formatTable)(y,r);m=m.setOffset((0,We._computeNewOffset)(m,y,S,!0));let V=S.table.toLines();m.column>S.table.getHeaderWidth()-1&&(V[m.row]+=" ",m=m.setOffset(1)),this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,V,c),this._selectFocus(l.start.row,S.table,m)}),r.smartCursor&&(this._scActive||(this._scActive=!0,this._scTablePos=l.start,P.column<0||S.table.getHeaderWidth()-1{let _=C,m=_;_.row===0?_.column>0&&(_=_.setColumn(_.column-1)):_.row===1?_=new _o.Focus(0,d.getHeaderWidth()-1,_.offset):_.column>0?_=_.setColumn(_.column-1):_=new _o.Focus(_.row===2?0:_.row-1,d.getHeaderWidth()-1,_.offset);let A=!_.posEquals(m),P=(0,Le.formatTable)(d,r);_=_.setOffset((0,We._computeNewOffset)(_,d,P,A)),this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,P.table.toLines(),c),A?this._selectFocus(l.start.row,P.table,_):this._moveToFocus(l.start.row,P.table,_)}),A&&this.resetSmartCursor()})}nextRow(r){this._withTable(r,({range:l,lines:c,table:d,focus:C})=>{let _=this._scTablePos!==void 0&&!l.start.equals(this._scTablePos)||this._scLastFocus!==void 0&&!C.posEquals(this._scLastFocus);this._scActive&&_&&this.resetSmartCursor();let m=C,A=(0,Le.completeTable)(d,r);A.delimiterInserted&&m.row>0&&(m=m.setRow(m.row+1));let P=m,y=A.table;if(m.row===0?m=m.setRow(2):m=m.setRow(m.row+1),r.smartCursor?this._scActive&&this._scStartFocus!==void 0?m=m.setColumn(this._scStartFocus.column):(m.column<0||y.getHeaderWidth()-1y.getHeight()-1){let V=new Array(y.getHeaderWidth()).fill(new un.TableCell(""));y=(0,Le.insertRow)(y,y.getHeight(),new Hr.TableRow(V,"",""))}let S=(0,Le.formatTable)(y,r);m=m.setOffset((0,We._computeNewOffset)(m,y,S,!0)),this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,S.table.toLines(),c),this._selectFocus(l.start.row,S.table,m)}),r.smartCursor&&(this._scActive||(this._scActive=!0,this._scTablePos=l.start,P.column<0||S.table.getHeaderWidth()-1{let m=_;m.row<=1&&(m=m.setRow(2)),m=m.setColumn(0);let A=new Array(C.getHeaderWidth()).fill(new un.TableCell("")),P=(0,Le.insertRow)(C,m.row,new Hr.TableRow(A,"",""));this.formatAndApply(r,l,c,d,P,m)})}deleteRow(r){this.withCompletedTable(r,({range:l,lines:c,formulaLines:d,table:C,focus:_})=>{let m=_,A=C,P=!1;m.row!==1&&(A=(0,Le.deleteRow)(A,m.row),P=!0,m.row>A.getHeight()-1&&(m=m.setRow(m.row===2?0:m.row-1))),this.formatAndApply(r,l,c,d,A,m,P)})}moveRow(r,l){this.withCompletedTable(l,({range:c,lines:d,formulaLines:C,table:_,focus:m})=>{let A=m,P=_;if(A.row>1){let y=Math.min(Math.max(A.row+r,2),P.getHeight()-1);P=(0,Le.moveRow)(P,A.row,y),A=A.setRow(y)}this.formatAndApply(l,c,d,C,P,A)})}evaluateFormulas(r){return this.withCompletedTable(r,({range:l,lines:c,formulaLines:d,table:C,focus:_})=>{let m=C.applyFormulas(d);if(m.isErr())return m.error;let{table:A,focus:P}=this.formatAndApply(r,l,c,d,m.value,_,!1)})}transpose(r){this.withCompletedTable(r,({range:l,lines:c,formulaLines:d,table:C,focus:_})=>{var m,A,P,y,S,V,M,Y;let se=C.getWidth(),ge=C.getHeight(),D=new Array(se+1);for(let te=0;te1){let G=(y=(P=C.getCellAt(Q,te))===null||P===void 0?void 0:P.content)!==null&&y!==void 0?y:"";J[Q-1]=new un.TableCell(G)}}D[te]=new Hr.TableRow(J,"","")}else if(te===1){let J=new Array(ge-1);for(let Q=0;Q1){let J=new Array(ge-1);for(let Q=0;Q1){let G=(Y=(M=C.getCellAt(Q,te-1))===null||M===void 0?void 0:M.content)!==null&&Y!==void 0?Y:"";J[Q-1]=new un.TableCell(G)}}D[te]=new Hr.TableRow(J,"","")}let $=new ou.Table(D),{table:U,focus:K}=this.formatAndApply(r,l,c,d,$,_,!0);this._moveToFocus(l.start.row,U,K)})}sortRows(r,l){this.withCompletedTable(l,({range:c,lines:d,formulaLines:C,table:_,focus:m})=>{let A=_.getRows().slice(2),P=se=>/^\s*[-+]?((\d+(\.\d+)?)|(\d+\.)|(\.\d+))([eE][-+]?\d+)?\s*$/.test(se),y=A.map(se=>{var ge;return(ge=se.getCellAt(m.column))===null||ge===void 0?void 0:ge.content}).some(se=>se!==void 0&&se!==""&&!P(se));A.sort((se,ge)=>{let D=se.getCellAt(m.column),$=ge.getCellAt(m.column);if(D===void 0||D.content==="")return $===void 0||$.content===""?0:-1;if($===void 0||$.content==="")return 1;let U=y?D.content.replace(/[*~_$]/g,""):parseFloat(D.content),K=y?$.content.replace(/[*~_$]/g,""):parseFloat($.content);return U===K?0:U===void 0?-1:K===void 0?1:U{let m=_;m.row===1&&(m=m.setRow(0)),m.column<0&&(m=m.setColumn(0));let A=new Array(C.getHeight()-1).fill(new un.TableCell("")),P=(0,Le.insertColumn)(C,m.column,A,r);this.formatAndApply(r,l,c,d,P,m)})}deleteColumn(r){this.withCompletedTable(r,({range:l,lines:c,formulaLines:d,table:C,focus:_})=>{let m=_;m.row===1&&(m=m.setRow(0));let A=C,P=!1;0<=m.column&&m.column<=A.getHeaderWidth()-1&&(A=(0,Le.deleteColumn)(C,m.column,r),P=!0,m.column>A.getHeaderWidth()-1&&(m=m.setColumn(A.getHeaderWidth()-1))),this.formatAndApply(r,l,c,d,A,m,P)})}moveColumn(r,l){this.withCompletedTable(l,({range:c,lines:d,formulaLines:C,table:_,focus:m})=>{let A=m,P=_;if(0<=A.column&&A.column<=P.getHeaderWidth()-1){let y=Math.min(Math.max(A.column+r,0),P.getHeaderWidth()-1);P=(0,Le.moveColumn)(P,A.column,y),A=A.setColumn(y)}this.formatAndApply(l,c,d,C,P,A)})}formatAll(r){this._textEditor.transact(()=>{let l=(0,We._createIsTableRowRegex)(r.leftMarginChars),c=this._textEditor.getCursorPosition(),d=[],C,_=this._textEditor.getLastRow();for(let m=0;m<=_;m++){let A=this._textEditor.getLine(m);if(this._textEditor.acceptsTableEdit(m)&&l.test(A))d.push(A),C===void 0&&(C=m);else if(C!==void 0){let P=m-1,y=new J3.Range(new ln.Point(C,0),new ln.Point(P,d[d.length-1].length)),S=(0,Br.readTable)(d,r),V=S.focusOfPosition(c,C),M;if(V!==void 0){let Y=V,se=(0,Le.completeTable)(S,r);se.delimiterInserted&&Y.row>0&&(Y=Y.setRow(Y.row+1));let ge=(0,Le.formatTable)(se.table,r);Y=Y.setOffset((0,We._computeNewOffset)(Y,se.table,ge,!1));let D=ge.table.toLines();this._updateLines(y.start.row,y.end.row+1,D,d),M=D.length-d.length,c=ge.table.positionOfFocus(Y,C)}else{let Y=(0,Le.completeTable)(S,r),ge=(0,Le.formatTable)(Y.table,r).table.toLines();this._updateLines(y.start.row,y.end.row+1,ge,d),M=ge.length-d.length,c.row>P&&(c=new ln.Point(c.row+M,c.column))}d=[],C=void 0,_+=M,m+=M}}if(C!==void 0){let m=_,A=new J3.Range(new ln.Point(C,0),new ln.Point(m,d[d.length-1].length)),P=(0,Br.readTable)(d,r),S=P.focusOfPosition(c,C),V=(0,Le.completeTable)(P,r);V.delimiterInserted&&S.row>0&&(S=S.setRow(S.row+1));let M=(0,Le.formatTable)(V.table,r);S=S.setOffset((0,We._computeNewOffset)(S,V.table,M,!1));let Y=M.table.toLines();this._updateLines(A.start.row,A.end.row+1,Y,d),c=M.table.positionOfFocus(S,C)}this._textEditor.setCursorPosition(c)})}exportTable(r,l){return this.withCompletedTable(l,({range:c,lines:d,formulaLines:C,table:_,focus:m})=>{let A=_.getRows();return A.length>0&&!r&&A.splice(0,2),A.map(P=>P.getCells().map(y=>y.content))})}exportCSV(r,l){let c=this.exportTable(r,l);return c?c.map(d=>d.join(" ")).join(` +`):void 0}withCompletedTable(r,l){return this._withTable(r,c=>{let d=c.focus,C=(0,Le.completeTable)(c.table,r);C.delimiterInserted&&d.row>0&&(d=d.setRow(d.row+1));let _=(0,Le.formatTable)(C.table,r);return d=d.setOffset((0,We._computeNewOffset)(d,C.table,_,!1)),c.table=_.table,c.focus=d,l(c)})}formatAndApply(r,l,c,d,C,_,m=!1){let A=(0,Le.formatTable)(C,r);return _=_.setOffset((0,We._computeNewOffset)(_,C,A,m)),this._textEditor.transact(()=>{this._updateLines(l.start.row,l.end.row+1,A.table.toLines(),c),m?this._selectFocus(l.start.row,A.table,_):this._moveToFocus(l.start.row,A.table,_)}),this.resetSmartCursor(),{range:l,lines:c,formulaLines:d,table:A.table,focus:_}}};We.TableEditor=Q3});var Mi=we(re=>{"use strict";Object.defineProperty(re,"__esModule",{value:!0});re.SortOrder=re.TableEditor=re.optionsWithDefaults=re.defaultOptions=re.ITextEditor=re.shortestEditScript=re.applyEditScript=re.Delete=re.Insert=re.moveColumn=re.deleteColumn=re.insertColumn=re.moveRow=re.deleteRow=re.insertRow=re.alterAlignment=re.formatTable=re.completeTable=re.FormatType=re.readTable=re.Table=re.TableRow=re.TableCell=re.HeaderAlignment=re.DefaultAlignment=re.Alignment=re.Focus=re.Range=re.Point=void 0;var j7=O1();Object.defineProperty(re,"Point",{enumerable:!0,get:function(){return j7.Point}});var ef=P1();Object.defineProperty(re,"Range",{enumerable:!0,get:function(){return ef.Range}});var tf=W1();Object.defineProperty(re,"Focus",{enumerable:!0,get:function(){return tf.Focus}});var j3=vi();Object.defineProperty(re,"Alignment",{enumerable:!0,get:function(){return j3.Alignment}});Object.defineProperty(re,"DefaultAlignment",{enumerable:!0,get:function(){return j3.DefaultAlignment}});Object.defineProperty(re,"HeaderAlignment",{enumerable:!0,get:function(){return j3.HeaderAlignment}});var nf=Pr();Object.defineProperty(re,"TableCell",{enumerable:!0,get:function(){return nf.TableCell}});var rf=_i();Object.defineProperty(re,"TableRow",{enumerable:!0,get:function(){return rf.TableRow}});var of=Ii();Object.defineProperty(re,"Table",{enumerable:!0,get:function(){return of.Table}});var sf=$3();Object.defineProperty(re,"readTable",{enumerable:!0,get:function(){return sf.readTable}});var an=wo();Object.defineProperty(re,"FormatType",{enumerable:!0,get:function(){return an.FormatType}});Object.defineProperty(re,"completeTable",{enumerable:!0,get:function(){return an.completeTable}});Object.defineProperty(re,"formatTable",{enumerable:!0,get:function(){return an.formatTable}});Object.defineProperty(re,"alterAlignment",{enumerable:!0,get:function(){return an.alterAlignment}});Object.defineProperty(re,"insertRow",{enumerable:!0,get:function(){return an.insertRow}});Object.defineProperty(re,"deleteRow",{enumerable:!0,get:function(){return an.deleteRow}});Object.defineProperty(re,"moveRow",{enumerable:!0,get:function(){return an.moveRow}});Object.defineProperty(re,"insertColumn",{enumerable:!0,get:function(){return an.insertColumn}});Object.defineProperty(re,"deleteColumn",{enumerable:!0,get:function(){return an.deleteColumn}});Object.defineProperty(re,"moveColumn",{enumerable:!0,get:function(){return an.moveColumn}});var bo=K3();Object.defineProperty(re,"Insert",{enumerable:!0,get:function(){return bo.Insert}});Object.defineProperty(re,"Delete",{enumerable:!0,get:function(){return bo.Delete}});Object.defineProperty(re,"applyEditScript",{enumerable:!0,get:function(){return bo.applyEditScript}});Object.defineProperty(re,"shortestEditScript",{enumerable:!0,get:function(){return bo.shortestEditScript}});var lf=eu();Object.defineProperty(re,"ITextEditor",{enumerable:!0,get:function(){return lf.ITextEditor}});var lu=ru();Object.defineProperty(re,"defaultOptions",{enumerable:!0,get:function(){return lu.defaultOptions}});Object.defineProperty(re,"optionsWithDefaults",{enumerable:!0,get:function(){return lu.optionsWithDefaults}});var uu=su();Object.defineProperty(re,"TableEditor",{enumerable:!0,get:function(){return uu.TableEditor}});Object.defineProperty(re,"SortOrder",{enumerable:!0,get:function(){return uu.SortOrder}})});var ff={};p9(ff,{default:()=>No});module.exports=m9(ff);var Cl=require("obsidian"),N1={spreadsheet:` + + +`,alignLeft:` + + + + + + + +`,alignCenter:` + + + + + + + +`,alignRight:` + + + + + +`,deleteColumn:` + + + +`,deleteRow:` + + + + +`,insertColumn:` + + + + + + + +`,insertRow:` + + + + + + + +`,moveColumnLeft:` + + + + +`,moveColumnRight:` + + + + +`,moveRowDown:` + + + + +`,moveRowUp:` + + + + +`,transpose:` + + + + +`,sortAsc:` + + + + + + + +`,sortDesc:` + + + + + + + +`,formula:` + + + +`,help:` + + + + +`,csv:` + + +`,arrowenter:` + + +`,arrowtab:` + + +`},vl=()=>{Object.keys(N1).forEach(s=>{s!=="help"&&(0,Cl.addIcon)(s,N1[s])})};var Ao=y1(Mi()),e0={formatType:Ao.FormatType.NORMAL,showRibbonIcon:!0,bindEnter:!0,bindTab:!0},Eo=class{constructor(r){let l={...e0,...r};this.formatType=l.formatType,this.showRibbonIcon=l.showRibbonIcon,this.bindEnter=l.bindEnter,this.bindTab=l.bindTab}asOptions(){return(0,Ao.optionsWithDefaults)({formatType:this.formatType})}};var au=y1(Mi()),To=class{constructor(r,l,c){this.getCursorPosition=()=>{let r=this.editor.getCursor();return new au.Point(r.line,r.ch)};this.setCursorPosition=r=>{this.editor.setCursor({line:r.row,ch:r.column})};this.setSelectionRange=r=>{this.editor.setSelection({line:r.start.row,ch:r.start.column},{line:r.end.row,ch:r.end.column})};this.getLastRow=()=>this.editor.lastLine();this.acceptsTableEdit=r=>{let l=this.app.metadataCache.getFileCache(this.file);if(!(l!=null&&l.sections))return!0;let c=l.sections.find(C=>C.position.start.line<=r&&C.position.end.line>=r&&C.type!=="code"&&C.type!=="math");if(c===void 0)return!1;let d=c.position.start.line;return!(d>=0&&this.getLine(d)==="-tx-")};this.getLine=r=>this.editor.getLine(r);this.insertLine=(r,l)=>{r>this.getLastRow()?this.editor.replaceRange(` +`+l,{line:r,ch:0}):this.editor.replaceRange(l+` +`,{line:r,ch:0})};this.deleteLine=r=>{if(r===this.getLastRow()){let l=this.getLine(r);this.editor.replaceRange("",{line:r,ch:0},{line:r,ch:l.length})}else this.editor.replaceRange("",{line:r,ch:0},{line:r+1,ch:0})};this.replaceLines=(r,l,c)=>{let d=l-1,_=this.editor.getLine(d).length;this.editor.replaceRange(c.join(` +`),{line:r,ch:0},{line:d,ch:_})};this.transact=r=>{r()};this.app=r,this.file=l,this.editor=c}};var _n=y1(Mi()),Ro=require("obsidian"),bn=class{constructor(r,l,c,d){this.cursorIsInTableFormula=()=>this.mte.cursorIsInTableFormula(this.settings.asOptions());this.cursorIsInTable=()=>this.mte.cursorIsInTable(this.settings.asOptions());this.nextCell=()=>{this.mte.nextCell(this.settings.asOptions())};this.previousCell=()=>{this.mte.previousCell(this.settings.asOptions())};this.nextRow=()=>{this.mte.nextRow(this.settings.asOptions())};this.formatTable=()=>{this.mte.format(this.settings.asOptions())};this.formatAllTables=()=>{this.mte.formatAll(this.settings.asOptions())};this.insertColumn=()=>{this.mte.insertColumn(this.settings.asOptions())};this.insertRow=()=>{this.mte.insertRow(this.settings.asOptions())};this.leftAlignColumn=()=>{this.mte.alignColumn(_n.Alignment.LEFT,this.settings.asOptions())};this.centerAlignColumn=()=>{this.mte.alignColumn(_n.Alignment.CENTER,this.settings.asOptions())};this.rightAlignColumn=()=>{this.mte.alignColumn(_n.Alignment.RIGHT,this.settings.asOptions())};this.moveColumnLeft=()=>{this.mte.moveColumn(-1,this.settings.asOptions())};this.moveColumnRight=()=>{this.mte.moveColumn(1,this.settings.asOptions())};this.moveRowUp=()=>{this.mte.moveRow(-1,this.settings.asOptions())};this.moveRowDown=()=>{this.mte.moveRow(1,this.settings.asOptions())};this.deleteColumn=()=>{this.mte.deleteColumn(this.settings.asOptions())};this.deleteRow=()=>{this.mte.deleteRow(this.settings.asOptions())};this.sortRowsAsc=()=>{this.mte.sortRows(_n.SortOrder.Ascending,this.settings.asOptions())};this.sortRowsDesc=()=>{this.mte.sortRows(_n.SortOrder.Descending,this.settings.asOptions())};this.transpose=()=>{this.mte.transpose(this.settings.asOptions())};this.escape=()=>{this.mte.escape(this.settings.asOptions())};this.evaluateFormulas=()=>{let r=this.mte.evaluateFormulas(this.settings.asOptions());r&&new Ro.Notice(r.message)};this.exportCSVModal=()=>{new t0(this.app,this.mte,this.settings).open()};this.app=r,this.settings=d;let C=new To(r,l,c);this.mte=new _n.TableEditor(C)}},t0=class extends Ro.Modal{constructor(r,l,c){super(r),this.mte=l,this.settings=c}onOpen(){let{contentEl:r}=this,l=r.createDiv({cls:"advanced-tables-csv-export"}),c=l.createEl("textarea",{attr:{readonly:!0}});c.value=this.mte.exportCSV(!0,this.settings.asOptions()),c.onClickEvent(()=>c.select());let d=l.createEl("label"),C=d.createEl("input",{type:"checkbox",attr:{checked:!0}});d.createSpan().setText("Include table headers"),C.onClickEvent(()=>{c.value=this.mte.exportCSV(C.checked,this.settings.asOptions())})}onClose(){let{contentEl:r}=this;r.empty()}};var zr=require("obsidian"),$r="advanced-tables-toolbar",xo=class extends zr.ItemView{constructor(l,c){super(l);this.draw=()=>{let l=this.containerEl.children[1],c=activeDocument.createElement("div");c.addClass("advanced-tables-buttons"),c.createDiv().createSpan({cls:"title"}).setText("Advanced Tables");let d=c.createDiv({cls:"nav-header"}),C=d.createDiv({cls:"nav-buttons-container"});C.createSpan({cls:"advanced-tables-row-label"}).setText("Align:"),this.drawBtn(C,"alignLeft","left align column",y=>y.leftAlignColumn()),this.drawBtn(C,"alignCenter","center align column",y=>y.centerAlignColumn()),this.drawBtn(C,"alignRight","right align column",y=>y.rightAlignColumn());let _=d.createDiv({cls:"nav-buttons-container"});_.createSpan({cls:"advanced-tables-row-label"}).setText("Move:"),this.drawBtn(_,"moveRowDown","move row down",y=>y.moveRowDown()),this.drawBtn(_,"moveRowUp","move row up",y=>y.moveRowUp()),this.drawBtn(_,"moveColumnRight","move column right",y=>y.moveColumnRight()),this.drawBtn(_,"moveColumnLeft","move column left",y=>y.moveColumnLeft()),this.drawBtn(_,"transpose","transpose",y=>y.transpose());let m=d.createDiv({cls:"nav-buttons-container"});m.createSpan({cls:"advanced-tables-row-label"}).setText("Edit:"),this.drawBtn(m,"insertRow","insert row above",y=>y.insertRow()),this.drawBtn(m,"insertColumn","insert column left",y=>y.insertColumn()),this.drawBtn(m,"deleteRow","delete row",y=>y.deleteRow()),this.drawBtn(m,"deleteColumn","delete column",y=>y.deleteColumn());let A=d.createDiv({cls:"nav-buttons-container"});A.createSpan({cls:"advanced-tables-row-label"}).setText("Sort/F:"),this.drawBtn(A,"sortAsc","sort by column ascending",y=>y.sortRowsAsc()),this.drawBtn(A,"sortDesc","sort by column descending",y=>y.sortRowsDesc()),this.drawBtn(A,"formula","evaluate formulas",y=>y.evaluateFormulas());let P=d.createDiv({cls:"nav-buttons-container"});P.createSpan({cls:"advanced-tables-row-label"}).setText("Misc:"),this.drawBtn(P,"csv","export as csv",y=>y.exportCSVModal()),this.drawBtn(P,"help","help",()=>activeWindow.open("https://github.com/tgrosinger/advanced-tables-obsidian/blob/main/docs/help.md")),l.empty(),l.appendChild(c)};this.drawBtn=(l,c,d,C)=>{let _=A=>d==="evaluate formulas"?A.cursorIsInTable()||A.cursorIsInTableFormula():A.cursorIsInTable(),m=l.createDiv({cls:"advanced-tables-button nav-action-button",title:d});m.onClickEvent(()=>this.withTE(C,_)),m.appendChild(uf(N1[c]))};this.withTE=(l,c,d=!0)=>{let C,_=this.app.workspace.getMostRecentLeaf();if(_.view instanceof zr.MarkdownView)C=_.view.editor;else{console.warn("Advanced Tables: Unable to determine current editor.");return}let m=new bn(this.app,_.view.file,C,this.settings);if(!c(m)){d&&new zr.Notice("Advanced Tables: Cursor must be in a table.");return}l(m)};this.settings=c}getViewType(){return $r}getDisplayText(){return"Advanced Tables"}getIcon(){return"spreadsheet"}load(){super.load(),this.draw()}},uf=s=>new DOMParser().parseFromString(s,"text/xml").documentElement;var fu=require("@codemirror/state"),hu=require("@codemirror/view"),yo=y1(Mi()),it=require("obsidian"),No=class extends it.Plugin{constructor(){super(...arguments);this.makeEditorExtension=()=>{let l=[];return this.settings.bindEnter&&l.push({key:"Enter",run:()=>this.newPerformTableActionCM6(c=>c.nextRow())(),preventDefault:!0}),this.settings.bindTab&&l.push({key:"Tab",run:()=>this.newPerformTableActionCM6(c=>c.nextCell())(),shift:()=>this.newPerformTableActionCM6(c=>c.previousCell())(),preventDefault:!0}),fu.Prec.highest(hu.keymap.of(l))};this.newPerformTableActionCM6=l=>()=>{let c=this.app.workspace.getActiveViewOfType(it.MarkdownView);if(c){let d=c.currentMode;if("sourceMode"in d&&!d.sourceMode)return!1;let C=new bn(this.app,c.file,c.editor,this.settings);if(C.cursorIsInTable())return l(C),!0}return!1};this.newPerformTableAction=(l,c=!0)=>(d,C,_)=>{let m=new bn(this.app,_.file,C,this.settings);if(d)return m.cursorIsInTable();l(m)};this.handleKeyDown=(l,c)=>{if(["Tab","Enter"].contains(c.key)){let d=this.app.workspace.getActiveViewOfType(it.MarkdownView),C=d?d.editor:null,_=this.newPerformTableAction(m=>{switch(c.key){case"Tab":if(!this.settings.bindTab)return;c.shiftKey?m.previousCell():m.nextCell();break;case"Enter":if(!this.settings.bindEnter)return;if(c.shiftKey)m.escape();else{if(c.ctrlKey||c.metaKey||c.altKey)return;m.nextRow()}break}c.preventDefault()},!1);_(!0,C,d)&&_(!1,C,d)}};this.toggleTableControlsView=async()=>{let l=this.app.workspace.getLeavesOfType($r);if(l.length){this.app.workspace.revealLeaf(l[0]);return}await this.app.workspace.getRightLeaf(!1).setViewState({type:$r,active:!0}),this.app.workspace.revealLeaf(this.app.workspace.getLeavesOfType($r)[0])};this.isMobile=()=>this.app.isMobile}async onload(){console.log("loading markdown-table-editor plugin"),await this.loadSettings(),this.registerView($r,l=>new xo(l,this.settings)),vl(),this.settings.showRibbonIcon&&this.addRibbonIcon("spreadsheet","Advanced Tables Toolbar",()=>{this.toggleTableControlsView()}),this.registerEditorExtension(this.makeEditorExtension()),this.addCommand({id:"next-row",name:"Go to next row",icon:"arrowenter",editorCheckCallback:this.newPerformTableAction(l=>{this.settings.bindEnter&&!this.isMobile&&new it.Notice("Advanced Tables: Next row also bound to enter. Possibly producing double actions. See Advanced Tables settings."),l.nextRow()})}),this.addCommand({id:"next-cell",name:"Go to next cell",icon:"arrowtab",editorCheckCallback:this.newPerformTableAction(l=>{this.settings.bindTab&&!this.isMobile&&new it.Notice("Advanced Tables: Next cell also bound to tab. Possibly producing double actions. See Advanced Tables settings."),l.nextCell()})}),this.addCommand({id:"previous-cell",name:"Go to previous cell",editorCheckCallback:this.newPerformTableAction(l=>{this.settings.bindTab&&!this.isMobile&&new it.Notice("Advanced Tables: Previous cell also bound to shift+tab. Possibly producing double actions. See Advanced Tables settings."),l.previousCell()})}),this.addCommand({id:"format-table",name:"Format table at the cursor",editorCheckCallback:this.newPerformTableAction(l=>{l.formatTable()})}),this.addCommand({id:"format-all-tables",name:"Format all tables in this file",editorCallback:(l,c)=>{new bn(this.app,c.file,l,this.settings).formatAllTables()}}),this.addCommand({id:"insert-column",name:"Insert column before current",icon:"insertColumn",editorCheckCallback:this.newPerformTableAction(l=>{l.insertColumn()})}),this.addCommand({id:"insert-row",name:"Insert row before current",icon:"insertRow",editorCheckCallback:this.newPerformTableAction(l=>{l.insertRow()})}),this.addCommand({id:"escape-table",name:"Move cursor out of table",editorCheckCallback:this.newPerformTableAction(l=>{l.escape()})}),this.addCommand({id:"left-align-column",name:"Left align column",icon:"alignLeft",editorCheckCallback:this.newPerformTableAction(l=>{l.leftAlignColumn()})}),this.addCommand({id:"center-align-column",name:"Center align column",icon:"alignCenter",editorCheckCallback:this.newPerformTableAction(l=>{l.centerAlignColumn()})}),this.addCommand({id:"right-align-column",name:"Right align column",icon:"alignRight",editorCheckCallback:this.newPerformTableAction(l=>{l.rightAlignColumn()})}),this.addCommand({id:"move-column-left",name:"Move column left",icon:"moveColumnLeft",editorCheckCallback:this.newPerformTableAction(l=>{l.moveColumnLeft()})}),this.addCommand({id:"move-column-right",name:"Move column right",icon:"moveColumnRight",editorCheckCallback:this.newPerformTableAction(l=>{l.moveColumnRight()})}),this.addCommand({id:"move-row-up",name:"Move row up",icon:"moveRowUp",editorCheckCallback:this.newPerformTableAction(l=>{l.moveRowUp()})}),this.addCommand({id:"move-row-down",name:"Move row down",icon:"moveRowDown",editorCheckCallback:this.newPerformTableAction(l=>{l.moveRowDown()})}),this.addCommand({id:"delete-column",name:"Delete column",icon:"deleteColumn",editorCheckCallback:this.newPerformTableAction(l=>{l.deleteColumn()})}),this.addCommand({id:"delete-row",name:"Delete row",icon:"deleteRow",editorCheckCallback:this.newPerformTableAction(l=>{l.deleteRow()})}),this.addCommand({id:"sort-rows-ascending",name:"Sort rows ascending",icon:"sortAsc",editorCheckCallback:this.newPerformTableAction(l=>{l.sortRowsAsc()})}),this.addCommand({id:"sort-rows-descending",name:"Sort rows descending",icon:"sortDesc",editorCheckCallback:this.newPerformTableAction(l=>{l.sortRowsDesc()})}),this.addCommand({id:"transpose",name:"Transpose",icon:"transpose",editorCheckCallback:this.newPerformTableAction(l=>{l.transpose()})}),this.addCommand({id:"evaluate-formulas",name:"Evaluate table formulas",icon:"formula",editorCheckCallback:(l,c,d)=>{let C=new bn(this.app,d.file,c,this.settings);if(l)return C.cursorIsInTable()||C.cursorIsInTableFormula();C.evaluateFormulas()}}),this.addCommand({id:"table-control-bar",name:"Open table controls toolbar",hotkeys:[{modifiers:["Mod","Shift"],key:"d"}],callback:()=>{this.toggleTableControlsView()}}),this.addSettingTab(new n0(this.app,this))}async loadSettings(){let l=Object.assign(e0,await this.loadData());this.settings=new Eo(l),await this.saveData(this.settings)}},n0=class extends it.PluginSettingTab{constructor(r,l){super(r,l),this.plugin=l}display(){let{containerEl:r}=this;r.empty(),new it.Setting(r).setName("Bind enter to table navigation").setDesc('Requires restart of Obsidian. If enabled, when the cursor is in a table, enter advances to the next row. Disabling this can help avoid conflicting with tag or CJK autocompletion. If disabling, bind "Go to ..." in the Obsidian Hotkeys settings.').addToggle(C=>C.setValue(this.plugin.settings.bindEnter).onChange(_=>{this.plugin.settings.bindEnter=_,this.plugin.saveData(this.plugin.settings),this.display()})),new it.Setting(r).setName("Bind tab to table navigation").setDesc('Requires restart of Obsidian. If enabled, when the cursor is in a table, tab/shift+tab navigate between cells. Disabling this can help avoid conflicting with tag or CJK autocompletion. If disabling, bind "Go to ..." in the Obsidian Hotkeys settings.').addToggle(C=>C.setValue(this.plugin.settings.bindTab).onChange(_=>{this.plugin.settings.bindTab=_,this.plugin.saveData(this.plugin.settings),this.display()})),new it.Setting(r).setName("Pad cell width using spaces").setDesc("If enabled, table cells will have spaces added to match the width of the longest cell in the column.").addToggle(C=>C.setValue(this.plugin.settings.formatType===yo.FormatType.NORMAL).onChange(_=>{this.plugin.settings.formatType=_?yo.FormatType.NORMAL:yo.FormatType.WEAK,this.plugin.saveData(this.plugin.settings),this.display()})),new it.Setting(r).setName("Show icon in sidebar").setDesc("If enabled, a button which opens the table controls toolbar will be added to the Obsidian sidebar. The toolbar can also be opened with a Hotkey. Changes only take effect on reload.").addToggle(C=>C.setValue(this.plugin.settings.showRibbonIcon).onChange(_=>{this.plugin.settings.showRibbonIcon=_,this.plugin.saveData(this.plugin.settings),this.display()}));let l=r.createEl("div",{cls:"advanced-tables-donation"}),c=activeDocument.createElement("p");c.appendText("If this plugin adds value for you and you would like to help support continued development, please use the buttons below:"),l.appendChild(c);let d=new DOMParser;l.appendChild(cu("https://paypal.me/tgrosinger",d.parseFromString(cf,"text/xml").documentElement)),l.appendChild(cu("https://www.buymeacoffee.com/tgrosinger",d.parseFromString(af,"text/xml").documentElement))}},cu=(s,r)=>{let l=activeDocument.createElement("a");return l.setAttribute("href",s),l.addClass("advanced-tables-donate-button"),l.appendChild(r),l},af=` + + + + + + + + + + + + + + + + + + + + + +`,cf=` + + + + + + + +`; +/*! Bundled license information: + +decimal.js/decimal.js: + (*! + * decimal.js v10.4.3 + * An arbitrary-precision Decimal type for JavaScript. + * https://github.com/MikeMcl/decimal.js + * Copyright (c) 2022 Michael Mclaughlin + * MIT Licence + *) + +lodash/lodash.js: + (** + * @license + * Lodash + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + *) +*/ + +/* nosourcemap */ \ No newline at end of file diff --git a/.obsidian/plugins/table-editor-obsidian/manifest.json b/.obsidian/plugins/table-editor-obsidian/manifest.json new file mode 100644 index 0000000..c57af31 --- /dev/null +++ b/.obsidian/plugins/table-editor-obsidian/manifest.json @@ -0,0 +1,15 @@ +{ + "id": "table-editor-obsidian", + "name": "Advanced Tables", + "author": "Tony Grosinger", + "authorUrl": "https://grosinger.net", + "description": "Improved table navigation, formatting, manipulation, and formulas.", + "isDesktopOnly": false, + "minAppVersion": "1.0.0", + "version": "0.22.2", + "fundingUrl": { + "Github Sponsor": "https://github.com/sponsors/tgrosinger", + "Buy me a Coffee": "https://buymeacoffee.com/tgrosinger", + "Paypal": "https://paypal.me/tgrosinger" + } +} diff --git a/.obsidian/plugins/table-editor-obsidian/styles.css b/.obsidian/plugins/table-editor-obsidian/styles.css new file mode 100644 index 0000000..089b8cd --- /dev/null +++ b/.obsidian/plugins/table-editor-obsidian/styles.css @@ -0,0 +1,78 @@ +:root { + --advanced-tables-helper-size: 28px; +} + +.HyperMD-table-row span.cm-inline-code { + font-size: 100%; + padding: 0px; +} + +.advanced-tables-buttons>div>.title { + font-weight: var(--font-medium); + font-size: var(--nav-item-size); + color: var(--nav-item-color); + text-decoration: underline; +} + +[data-type="advanced-tables-toolbar"] .nav-buttons-container { + column-gap: 0.2rem; + margin: 0.2rem 0 0.2rem 0; + justify-content: start; +} + +[data-type="advanced-tables-toolbar"] .nav-buttons-container::before { + min-width: 2.6rem; + line-height: var(--advanced-tables-helper-size); + font-size: var(--nav-item-size); + font-weight: var(--nav-item-weight); + color: var(--nav-item-color); +} + +[data-type="advanced-tables-toolbar"] .nav-buttons-container>* { + height: var(--advanced-tables-helper-size); + line-height: var(--advanced-tables-helper-size); +} + +[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button { + width: var(--advanced-tables-helper-size); + height: var(--advanced-tables-helper-size); + display: flex; + justify-content: center; + align-items: center; + border-radius: var(--radius-s); +} + +[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button:hover { + background-color: var(--nav-item-background-hover); + color: var(--nav-item-color-hover); + font-weight: var(--nav-item-weight-hover); +} + +.advanced-tables-row-label { + width: 50px; +} + +.widget-icon { + width: 20px; + height: 20px; + fill: var(--text-muted); +} + +.widget-icon:hover { + fill: var(--text-normal); +} + +.advanced-tables-csv-export textarea { + height: 200px; + width: 100%; +} + +.advanced-tables-donation { + width: 70%; + margin: 0 auto; + text-align: center; +} + +.advanced-tables-donate-button { + margin: 10px; +} \ No newline at end of file diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json new file mode 100644 index 0000000..528f847 --- /dev/null +++ b/.obsidian/workspace.json @@ -0,0 +1,219 @@ +{ + "main": { + "id": "f4001d5cca899f5a", + "type": "split", + "children": [ + { + "id": "0e934a456bebf576", + "type": "tabs", + "children": [ + { + "id": "75e85cb517113c51", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + } + ] + } + ], + "direction": "vertical" + }, + "left": { + "id": "4c0c7eedd8a95dba", + "type": "split", + "children": [ + { + "id": "1bd64000bb3e2a1d", + "type": "tabs", + "children": [ + { + "id": "33194498fe34f93e", + "type": "leaf", + "state": { + "type": "file-explorer", + "state": { + "sortOrder": "alphabetical", + "autoReveal": false + }, + "icon": "lucide-folder-closed", + "title": "Files" + } + }, + { + "id": "435ffcf39187a361", + "type": "leaf", + "state": { + "type": "search", + "state": { + "query": "", + "matchingCase": false, + "explainSearch": false, + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical" + }, + "icon": "lucide-search", + "title": "Search" + } + }, + { + "id": "d2954f42c4034efa", + "type": "leaf", + "state": { + "type": "bookmarks", + "state": {}, + "icon": "lucide-bookmark", + "title": "Bookmarks" + } + } + ] + } + ], + "direction": "horizontal", + "width": 300 + }, + "right": { + "id": "79ed81a665fe0794", + "type": "split", + "children": [ + { + "id": "16bc18f414a0483f", + "type": "tabs", + "children": [ + { + "id": "545b3438788eacf2", + "type": "leaf", + "state": { + "type": "backlink", + "state": { + "collapseAll": false, + "extraContext": false, + "sortOrder": "alphabetical", + "showSearch": false, + "searchQuery": "", + "backlinkCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-coming-in", + "title": "Backlinks" + } + }, + { + "id": "15ed6b36c33df3f4", + "type": "leaf", + "state": { + "type": "outgoing-link", + "state": { + "linksCollapsed": false, + "unlinkedCollapsed": true + }, + "icon": "links-going-out", + "title": "Outgoing links" + } + }, + { + "id": "4f926938fbc07ed1", + "type": "leaf", + "state": { + "type": "tag", + "state": { + "sortOrder": "frequency", + "useHierarchy": true, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-tags", + "title": "Tags" + } + }, + { + "id": "c86c9a26da434eb2", + "type": "leaf", + "state": { + "type": "all-properties", + "state": { + "sortOrder": "frequency", + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-archive", + "title": "All properties" + } + }, + { + "id": "70a1ac4b68780026", + "type": "leaf", + "state": { + "type": "outline", + "state": { + "followCursor": false, + "showSearch": false, + "searchQuery": "" + }, + "icon": "lucide-list", + "title": "Outline" + } + } + ], + "currentTab": 4 + } + ], + "direction": "horizontal", + "width": 300 + }, + "left-ribbon": { + "hiddenItems": { + "switcher:Open quick switcher": false, + "graph:Open graph view": false, + "canvas:Create new canvas": false, + "daily-notes:Open today's daily note": false, + "templates:Insert template": false, + "command-palette:Open command palette": false, + "bases:Create new base": false, + "table-editor-obsidian:Advanced Tables Toolbar": false + } + }, + "active": "75e85cb517113c51", + "lastOpenFiles": [ + "docs/10-验收检查清单.md", + "docs/05-API接口契约.md", + "docs/02-开发计划.md", + "sql/migrations/V1__initial_schema.sql", + "docs/03-数据库设计文档.md", + "scripts/test.sh", + "scripts/setup-test-db.sh", + "sql/migrations", + "sql", + "scripts", + "docs/09-项目目录结构.md", + "docs/07-环境配置.md", + "docs/06-UI交互规范.md", + "docs/01-需求清单/MOD-模块管理/REQ-MOD-004.md", + "docs/01-需求清单/MOD-模块管理/REQ-MOD-003.md", + "docs/01-需求清单/MOD-模块管理/_module.md", + "docs/01-需求清单/MOD-模块管理/REQ-MOD-002.md", + "docs/01-需求清单/MOD-模块管理/REQ-MOD-001.md", + "docs/01-需求清单/MOD-模块管理", + "docs/01-需求清单/USR-用户管理/_module.md", + "docs/01-需求清单/USR-用户管理/REQ-USR-004.md", + "docs/01-需求清单/USR-用户管理/REQ-USR-003.md", + "docs/01-需求清单/USR-用户管理/REQ-USR-002.md", + "docs/01-需求清单/USR-用户管理/REQ-USR-001.md", + "docs/01-需求清单/USR-用户管理", + "CLAUDE.md", + "docs/01-需求清单/index.md", + "docs/08-模块任务管理.md", + "docs/04-技术规范.md", + "docs/01-需求清单", + "docs", + "docs/superpowers/plans/2026-04-21-REQ-SYS-001.md", + "docs/superpowers/module-reports/module_sys-cross-module.md", + "docs/01-需求清单/SYS-系统管理.md", + "docs/01-需求清单/README.md", + "docs/superpowers/reviews/2026-04-21-REQ-SYS-001.md" + ] +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..44398a7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,218 @@ +# CLAUDE.md — ERP项目 Claude Code 主指令文件 + +> 本文件是 Claude Code 的"操作手册"。Claude Code 启动时会自动读取此文件。 + +--- + +## 🎯 项目概述 + +- **项目名称**: 小羚羊 +- **项目简述**: 测试ERP +- **目标用户**: 企业内部管理人员 +- **部署方式**: 私有化部署 + +--- + +## 🔄 B 阶段开发流程(模块循环 + 功能循环) + +两层嵌套循环**全部固化到 skills**。入口:`/erp-workflow:coding-start`。 + +- **模块循环(外)**:`module-start` → `test-gate` → `module-report` → `mr-create` → 人工 Approve MR → 下一模块 +- **功能循环(内,每 REQ-XXX-NNN 一遍)**:`feature-brainstorm` → `feature-plan` → `feature-tdd` → `feature-verify` → `feature-review` + +MR 前测试闸门: + - `test-gate`(子会话跑 `scripts/test.sh` 全量——本模块所有 REQ + 已完成模块回归); + - `.githooks/pre-push` 兜底 + - `git push --no-verify` 被 `deny-no-verify.sh` 硬拦。 + +--- + +## ✅ 模块完成判定规则 + +`docs/08-模块任务管理.md § 二` 是**模块元数据表**——每个模块记录依赖 / 路径 / MR iid / 功能(REQ)子项清单。**模块完成由 `MR:` 字段 + `GitLab API state=merged` 判定**;功能子项勾选只作可视化进度,不参与模块完成判定。 + +### 规则定义 + +每个模块在 docs/08 § 二 中长这样: + +```markdown +- module_0 系统管理 + - 依赖: — + - 路径: backend/module/sys/, frontend/pages/sys/ + - MR: — + - 功能: + - [ ] REQ-SYS-001 用户登录 + - [ ] REQ-SYS-002 用户注册 +``` + +- `MR:` 字段由 `mr-create` 在创建 MR 时从 `—` 改为 `!`。 +- 每个 `REQ-*` 子项由 `feature-review` 在 `verdict=approve` 时自动勾选为 `[x]` +- 子项全部勾选不等于模块完成,模块完成判定仍以 `MR:` + GitLab API state 为准。 + +### 模块状态语义 + +| `MR:` 字段 | `GitLab API state` | 含义 | 你(Claude Code)的行为 | +|---|---|---|---| +| `—` | — | 模块未开始(未创建 MR) | ✅ 开始本模块开发 | +| `!` | `opened` / `closed` | 模块开发中 / 打回 | ✅ 继续推进该模块 | +| `!` | `merged` | 模块**已完成** | 🟢 进入下一未完成模块 | + +### 模块完成报告 + +由 `module-report` skill 产出,模板位于 由 module-report skill 持有(12 节标准化,含跨模块改动等 CLAUDE.md 软规则映射节)。CC 不手写模块报告,仅填模板。 + +--- + +## 🏷️ 占位符统一约定 + +项目文档里有 **2 种填写占位** + **1 种提示占位**: + +| 格式 | 谁填 | 使用阶段 | 说明 | +|------|-----|---------|------| +| `【人工填写:<简短说明>】` | 人 | 仅 A 阶段文档 | 密钥 / 账密 / 包名 / 命名约定 / 小版本号等人工才能决定的值;B 阶段 plan/spec 禁止出现,查不到真值时用 `AskUserQuestion` 问用户 | +| `TBD(<责任人>)` | CC 自动 | A 或 B | 后缀附带责任方(如 `TBD(A3 自动补)` / `TBD(A5 自动补)`);由对应 skill 就地补填,`module-report` § ⑦ 检查 `TBD(CC 补)` 残留 | + +**HTML 注释 ``**:提示占位,是**插件内部大纲模板**里给 LLM 的**填空提示 / 章节引导**,指引 LLM 按结构填实际内容。skill 生成时会**剥除**这些注释,最终产物里注释不会保留。 + +--- + +## 📐 编码行为约束 + +### 你必须做的 ✅ + +1. **严格遵循** `docs/04-技术规范.md`——命名 / 编码 / 统一响应 / 异常处理 / 数据访问 / 配置与安全 等项目专属技术规约全部在此 +2. **严格遵循** `docs/09-项目目录结构.md`——文件放对位置 +3. **每个后端接口** 必须先在 `docs/05-API接口契约.md` 定义,再编码实现 +4. **每个功能可追溯到 `REQ-XXX-NNN`**——commit tag + 代码注释(如 `// REQ-SYS-001: 用户登录`)+ plan/spec 文件名均用此 tag +5. **遇到跨模块改动**(动到非当前模块的代码)——按 § 🟡 软规则 **S2** 执行(允许改,但必须留痕) +6. **遇到技术栈外组件引入**(`docs/04 § 零` 技术栈表外的框架 / 中间件 / 关键库),按 § 🟡 软规则 **S1** 执行(允许引入,但必须先 AskUserQuestion) + +### 你禁止做的 🚫 + +1. **主会话直接 `mysql -e` 跑业务 DDL**(只读查询 / 临时本地调试除外)——业务 schema 必须走 `sql/migrations/V_n__*.sql`,详见下方 Schema 演化规约 +2. **手动 Edit `docs/08 § 二` 的 `MR:` 字段**,必须要由 `mr-create` 自动回写 + +### Schema 演化规约(Flyway migration) + +1. **文件命名**:`sql/migrations/V__.sql`,例:`V5__add_user_email_unique_index.sql` +2. **版本号分配**:建文件前 `ls sql/migrations/V*.sql` 查当前最大 n,新文件 `n_max + 1` +3. **Apply 方式**:Spring Boot 启动 / 测试启动时 Flyway 自动 apply(项目必须在 `pom.xml` 声明 `flyway-core` + `flyway-mysql` 依赖)。`scripts/setup-test-db.sh` 只负责清空库,不做 apply +4. **已合并的 migration 永不修改**:发现错了写一个补救 migration(如 `V7__fix_V5_index_name.sql`),旧 `V_n.sql` +5. **临时调试 DDL**:临时在本地试字段/索引可手动 `mysql -e`,但不写 migration;下次 `setup-test-db.sh` 会 drop+create 清掉 +6. **A4 生成的 V1**:`V1__initial_schema.sql` 是 A 阶段由 `db-init` 从 `docs/03-数据库设计文档.md`(A3 正向设计的 schema SSoT)翻译生成的初始版本;后续 V2/V3/... 由 B 阶段每个 REQ 按需写入,**同时**反向同步更新 docs/03 对应表小节以保持 SSoT 一致 + +--- + +## 🗂️ Git 提交规范 + +每次提交必须遵循以下格式: + +``` +(): +``` + +- `scope`: 模块名,如 `user` / `inventory` / `order` +- `subject`: 简短描述;业务类(feat / fix / test)必须带 `REQ-XXX-NNN` 后缀 + +`type` 含义: + +| type | 看到它意味着 | +|-----|-------------| +| `feat` | **新能力上线**——用户多了一个功能、接口、页面或业务规则 | +| `fix` | **修 bug**——原来行为错了,这次改对 | +| `refactor` | **重构**——外部行为不变,只改代码结构 / 命名 / 抽象 | +| `docs` | **文档改动**——只动 Markdown / 代码注释,不动实现 | +| `style` | **格式调整**——空白 / 缩进 / import 顺序,逻辑 0 变化 | +| `test` | **只动测试代码**——补用例 / 修 fixture,不碰实现 | +| `chore` | **流程维护**——构建 / 依赖 / 工具 / 证据档案 / MR 元数据等非业务动作 | + +--- + +## 🚩 中断机制 + +功能循环(每个功能 REQ-XXX 的 Brainstorm → Plan → TDD → Verify → AI 自审)默认 **静默编程**,但触发以下任何一条必须**立刻停下、记录原因、等人决策**,不得自行绕过: + +| # | 中断 | 例子 | +| - | --- | --- | +| 1 | **测试反复失败** | 同一测试同一功能内连续 **10 次**修复失败 | +| 2 | **要改密钥 / 账密 / 包名** | `docs/07-环境配置.md` 里由人工标注必须填的字段 | +| 3 | **外部接口不可达** | 第三方 API 无法连接、证书失效等环境问题,并无法自行解决 | + +> 其余需要人类判断的场景一律走普通 `AskUserQuestion` Q&A,不中断、不写 Blocker 文件。 + +**触发中断时的固定动作:** + +1. 在当前功能的 plan 文件里追加一节 `## 🚩 Blocker`(报告格式由 `interrupt-check` 的 `interrupt-block-template.md` 持有) +2. 停止后续所有功能的静默执行 +3. 在主会话输出一句话摘要 + 指向 blocker 文件的路径,等人回复 + +--- + +## 🟡 软规则(允许继续,但有强制后续动作) + +以下情况 **不触发中断**,CC 可自行继续推进,但必须在约定位置留痕,模块完成时统一审计。 + +| # | 软规则 | 允许动作 | 强制后续 | +| - | ----- | ------- | ------- | +| S1 | **技术栈外组件引入** | 用 `AskUserQuestion` 给用户三选一:接受引入 / 换方案 / 拒绝 | ① **接受** → 同会话直接在 `docs/04 § 零` 追加一行 → 继续流程 ② **换方案 / 拒绝** → 视为常规歧义澄清,继续 Q&A 收敛 ③ 不写 Blocker、不中断流程 | +| S2 | **跨模块改动** | **默认不改**,仅为当前模块实现所必需时允许修改 | ① hook `log-cross-module.sh` 自动落存根 ② `module-report` 一次性调用 `cross-module-log` skill 批量补齐「原因 / 影响评估」+ 「跨模块改动」节完整贴入《模块完成报告》 | + +--- + +## 🧭 通用工作准则(General Principles) + +### 1. Think Before Coding + +**Don't assume. Don't hide confusion. Surface tradeoffs.** + +Before implementing: +- State your assumptions explicitly. If uncertain, ask. +- If multiple interpretations exist, present them - don't pick silently. +- If a simpler approach exists, say so. Push back when warranted. +- If something is unclear, stop. Name what's confusing. Ask. + +### 2. Simplicity First + +**Minimum code that solves the problem. Nothing speculative.** + +- No features beyond what was asked. +- No abstractions for single-use code. +- No "flexibility" or "configurability" that wasn't requested. +- No error handling for impossible scenarios. +- If you write 200 lines and it could be 50, rewrite it. + +Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify. + +### 3. Surgical Changes + +**Touch only what you must. Clean up only your own mess.** + +When editing existing code: +- Don't "improve" adjacent code, comments, or formatting. +- Don't refactor things that aren't broken. +- Match existing style, even if you'd do it differently. +- If you notice unrelated dead code, mention it - don't delete it. + +When your changes create orphans: +- Remove imports/variables/functions that YOUR changes made unused. +- Don't remove pre-existing dead code unless asked. + +The test: Every changed line should trace directly to the user's request. + +### 4. Goal-Driven Execution + +**Define success criteria. Loop until verified.** + +Transform tasks into verifiable goals: +- "Add validation" → "Write tests for invalid inputs, then make them pass" +- "Fix the bug" → "Write a test that reproduces it, then make it pass" +- "Refactor X" → "Ensure tests pass before and after" + +For multi-step tasks, state a brief plan: +``` +1. [Step] → verify: [check] +2. [Step] → verify: [check] +3. [Step] → verify: [check] +``` + +Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification. diff --git a/docs/01-需求清单/MOD-模块管理/REQ-MOD-001.md b/docs/01-需求清单/MOD-模块管理/REQ-MOD-001.md new file mode 100644 index 0000000..0df3434 --- /dev/null +++ b/docs/01-需求清单/MOD-模块管理/REQ-MOD-001.md @@ -0,0 +1,31 @@ +### REQ-MOD-001 模块新增 + +**目标**: 新增一个 ERP 业务模块定义,作为系统功能与权限分组的基础单位 + +- **输入**: + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | -------- | ---- | --- | ---- | ----------- | ---- | -------- | + | 显示类型 | 文本 | 是 | 下拉单选 | 手机端/前端业务/系统配置/接口 | 手机端 | — | + | 存储过程(审核)名称 | 文本 | 是 | 手工输入 | — | — | — | + | 模块类型 | 文本 | 是 | 手工输入 | — | — | — | + | 管理部门英文 | 文本 | 是 | 手工输入 | — | — | — | + | 权限是否显示 | 布尔 | 否 | 复选框 | — | 否 | — | + | 界面名称中文 | 文本 | 是 | 手工输入 | — | — | — | + +- **输出**: + + - **表1**: + + | 字段 | 类型 | 显示来源 | + | ----- | ---- | ----- | + | 模块 id | 文本 | `模块表` | + +- **跨字段规则**: - +- **边界**: 必填项不能为空 +- **验收**: 提交后模块记录持久化并返回新模块 id;字段格式错误或必填缺失时返回明确错误码并定位字段 +- **依赖表**: `tModule`(写) +- **依赖接口**: — + diff --git a/docs/01-需求清单/MOD-模块管理/REQ-MOD-002.md b/docs/01-需求清单/MOD-模块管理/REQ-MOD-002.md new file mode 100644 index 0000000..5421239 --- /dev/null +++ b/docs/01-需求清单/MOD-模块管理/REQ-MOD-002.md @@ -0,0 +1,30 @@ +### REQ-MOD-002 模块修改 + +**目标**: 在不破坏唯一性的前提下,更新已有模块的可编辑信息 + +- **输入**: 选中目标 + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | -------- | ---- | --- | ---- | ----------- | ---- | -------- | + | 显示类型 | 文本 | 是 | 下拉单选 | 手机端/前端业务/系统配置/接口 | 原值 | — | + | 存储过程(审核)名称 | 文本 | 是 | 手工输入 | — | 原值 | — | + | 模块类型 | 文本 | 是 | 手工输入 | — | 原值 | — | + | 管理部门英文 | 文本 | 是 | 手工输入 | — | 原值 | — | + | 权限是否显示 | 布尔 | 否 | 复选框 | — | 原值 | — | + | 界面名称中文 | 文本 | 是 | 手工输入 | — | 原值 | — | + +- **输出**: + + - **表1**: + + | 字段 | 类型 | 显示来源 | + | ----- | ---- | ----- | + | 模块 id | 文本 | `模块表` | + +- **跨字段规则**: - +- **边界**: 必须传入有效模块 id;字段格式与新增一致 +- **验收**: 提交后字段更新成功并返回模块 id;非法 id 或必填缺失时返回明确错误码并定位字段 +- **依赖表**: `tModule`(写) +- **依赖接口**: — diff --git a/docs/01-需求清单/MOD-模块管理/REQ-MOD-003.md b/docs/01-需求清单/MOD-模块管理/REQ-MOD-003.md new file mode 100644 index 0000000..fbae890 --- /dev/null +++ b/docs/01-需求清单/MOD-模块管理/REQ-MOD-003.md @@ -0,0 +1,21 @@ +### REQ-MOD-003 模块删除 + +**目标**: 删除一个已有模块,且不破坏数据引用完整性 + +- **输入**: + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | ----- | ---- | --- | ----- | ----- | --- | -------- | + | 模块 id | 文本 | — | 点击按钮 | — | — | — | + +- **输出**: 成功/失败 + +- **跨字段规则**: 已被业务引用(菜单 / 权限 / 用户角色等)的模块不允许直接删除;建议软删除并记录删除时间与操作人 +- **边界**: 必须传入有效模块 id;删除接口需具备相应权限并支持二次确认 +- **验收**: 合法删除返回成功状态;存在引用时返回拒绝原因与冲突来源;非法 id 给出明确错误码 +- **依赖表**: `tModule`(软删除写:`bDeleted` / `tDeletedDate` / `sDeletedBy`;删除前在 service 层检查子模块或外部引用) +- **依赖接口**: — + + diff --git a/docs/01-需求清单/MOD-模块管理/REQ-MOD-004.md b/docs/01-需求清单/MOD-模块管理/REQ-MOD-004.md new file mode 100644 index 0000000..11d39fb --- /dev/null +++ b/docs/01-需求清单/MOD-模块管理/REQ-MOD-004.md @@ -0,0 +1,32 @@ +### REQ-MOD-004 模块查询 + +**目标**: 按关键字检索模块,并以树形结构展示匹配结果 + +- **输入**: + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | --- | ---- | --- | ---- | ---- | --- | -------------- | + | 关键字 | 文本 | 否 | 手工输入 | — | — | 对界面名称模糊匹配;空为匹配所有 | + +- **输出**: + + - **表1**: + + | 字段 | 类型 | 显示来源 | + | ------ | ---- | ----- | + | 模块 id | 文本 | `模块表` | + | 界面名称中文 | 文本 | `模块表` | + | 显示类型 | 文本 | `模块表` | + | 管理部门英文 | 文本 | `模块表` | + | 父级 id | 文本 | `模块表` | + | 序号 | 数字 | `模块表` | + +- **跨字段规则**: - +- **边界**: 查询为只读,不产生写副作用;空关键字返回完整模块树 +- **验收**: 查询结果与库内数据一致;按界面名称模糊匹配生效;空结果返回空列表而非错误 +- **依赖表**: `tModule`(读,按 `sModuleNameZh` 模糊匹配 + 按 `iParentId` 拼装树形) +- **依赖接口**: — + + diff --git a/docs/01-需求清单/MOD-模块管理/_module.md b/docs/01-需求清单/MOD-模块管理/_module.md new file mode 100644 index 0000000..773527f --- /dev/null +++ b/docs/01-需求清单/MOD-模块管理/_module.md @@ -0,0 +1,5 @@ +# MOD-模块管理 + +- **模块简述**: 维护 ERP 业务模块的元数据,支持模块的增加、修改、删除和查询 +- **依赖模块**: — +- **涉及表**: `tModule` diff --git a/docs/01-需求清单/USR-用户管理/REQ-USR-001.md b/docs/01-需求清单/USR-用户管理/REQ-USR-001.md new file mode 100644 index 0000000..6f6e19a --- /dev/null +++ b/docs/01-需求清单/USR-用户管理/REQ-USR-001.md @@ -0,0 +1,41 @@ +### REQ-USR-001 用户新增 + +**目标**: 录入新用户的基本信息并完成账户初始化,便于后续登录与权限分配 + +- **输入**: + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | -------- | ---- | --- | ---- | ----------------- | --------- | ------------------- | + | 创建时间 | 日期时间 | — | 系统生成 | — | 当前日期 | 保存后自动生成;只读 | + | 制单人 | 文本 | — | 系统生成 | — | 当前登录用户 | 保存后自动生成;只读 | + | 员工名 | 文本 | 否 | 下拉单选 | `职员表` | — | 关联职员(可选) | + | 用户号 | 文本 | 是 | 手工输入 |— | — | 关联职员选择后自动输入员工姓名 | + | 用户名 | 文本 | 是 | 手工输入 |— | — | 关联职员选择后自动输入员工姓名 | + | 类型 | 文本 | 是 | 下拉单选 | 普通用户/超级管理员 | 普通用户 | — | + | 语言 | 文本 | 是 | 下拉单选 | 中文/英文/繁体 | — | — | + | 单据修改权限 | 布尔 | 否 | 复选框 | — | 否 | — | + | 密码 | 文本 | - | 系统生成 | 不显示 | 666666 | 保存后自动设为初始化 | + + - **表2** - 权限组: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | -------- | ---- | --- | ---- | ----------------- | --------- | ------------------- | + | 复选框 | 布尔 | 否 | 复选框 | — | 否 | 是否选择当前行权限 | + | 权限分类 | 文本 | — | — | — | — | — | + + +- **输出**: + + - **表1**: + + | 字段 | 类型 | 显示来源 | + | --- | --- | --- | + | 用户号 | 文本 | - | + +- **跨字段规则**: 用户名在系统内全局唯一;角色取值受系统配置约束 +- **边界**: 密码以哈希形式存储 +- **验收**: 提交合法表单后系统持久化用户记录并返回新用户 id;唯一性冲突或字段格式错误时返回明确错误码并定位到具体字段 +- **依赖表**: `tUser`(写)、`tStaff`(员工名下拉读)、`tPermissionCategory`(权限分类下拉读)、`tUserPermission`(写权限组关联) +- **依赖接口**: — diff --git a/docs/01-需求清单/USR-用户管理/REQ-USR-002.md b/docs/01-需求清单/USR-用户管理/REQ-USR-002.md new file mode 100644 index 0000000..07b4df5 --- /dev/null +++ b/docs/01-需求清单/USR-用户管理/REQ-USR-002.md @@ -0,0 +1,46 @@ +### REQ-USR-002 用户修改 + +**目标**: 在不破坏唯一性的前提下,更新已有用户的可编辑信息 + +- **输入**: 选中目标 + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | -------- | ---- | --- | ---- | ----------------- | --------- | ------------------- | + | 创建时间 | 日期时间 | — | 系统生成 | — | 原值 | 保存后自动生成;只读 | + | 制单人 | 文本 | — | 系统生成 | — | 原值 | 保存后自动生成;只读 | + | 员工名 | 文本 | 否 | 下拉单选 | `职员表` | 原值 | 关联职员(可选) | + | 用户号 | 文本 | 是 | 手工输入 |— | 原值 | 关联职员选择后自动输入员工姓名 | + | 用户名 | 文本 | 是 | 手工输入 |— | 原值 | 关联职员选择后自动输入员工姓名 | + | 类型 | 文本 | 是 | 下拉单选 | 普通用户/超级管理员 | 原值 | — | + | 语言 | 文本 | 是 | 下拉单选 | 中文/英文/繁体 | 原值 | — | + | 单据修改权限 | 布尔 | 否 | 复选框 | — | 原值 | — | + | 密码 | 文本 | - | 系统生成 | 不显示 | 原值 | 保存后自动设为初始化 | + + - **表2** - 权限组: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | -------- | ---- | --- | ---- | ----------------- | --------- | ------------------- | + | 复选框 | 布尔 | 否 | 复选框 | — | 原值 | 是否选择当前行的权限 | + | 权限分类 | 文本 | — | — | — | — | — | + +- **输出**: + + - **表1**: + + | 字段 | 类型 | 显示来源 | + | --- | --- | --- | + | 用户 id | 文本 | `职员表` | + +- **跨字段规则**: 密码不在该接口修改;角色变更需具备相应权限 +- **边界**: 必须传入有效用户 id;字段格式与新增一致 +- **验收**: 提交后字段更新成功并返回最新用户数据;非法 id、唯一冲突或格式错误返回明确错误码并定位字段 +- **依赖表**: `tUser`(写)、`tStaff`(员工名下拉读)、`tPermissionCategory`(权限分类下拉读)、`tUserPermission`(写权限组关联) +- **依赖接口**: — + + + + + | 创建时间 | 日期时间 | — | — | — | 原值 | 不变;只读 | + | 制单人 | 文本 | — | — | — | 原值 | 不变;只读 | \ No newline at end of file diff --git a/docs/01-需求清单/USR-用户管理/REQ-USR-003.md b/docs/01-需求清单/USR-用户管理/REQ-USR-003.md new file mode 100644 index 0000000..3f2836f --- /dev/null +++ b/docs/01-需求清单/USR-用户管理/REQ-USR-003.md @@ -0,0 +1,37 @@ +### REQ-USR-003 用户查询 + +**目标**: 按条件检索用户列表,并支持查看单个用户的详情 + +- **输入**: + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | ---- | ---- | --- | ---- | ----------------------------------------------- | ------- | --------------- | + | 查询字段 | 文本 | 否 | 下拉单选 | 用户名/员工名/用户号/部门/用户类型/作废/登录日期/制单人 | 用户名 | — | + | 匹配方式 | 文本 | 否 | 下拉单选 | 包含/不包含/等于 | 包含 | — | + | 查询值 | 文本 | 否 | 手工输入 | — | — | 与「查询字段」配合使用,空为选择全部 | + +- **输出**: + + - **表1**: + + | 字段 | 类型 | 显示来源 | + | ---- | ---- | ----- | + | 序号 | 数字 | 系统生成 | + | 用户名 | 文本 | `用户表` | + | 员工名 | 文本 | `职员表` | + | 用户号 | 文本 | `用户表` | + | 部门 | 文本 | `职员表` | + | 用户类型 | 文本 | `用户表` | + | 语言 | 文本 | `用户表` | + | 作废 | 布尔 | `用户表` | + | 登录日期 | 日期时间 | `用户表` | + | 制单人 | 文本 | `用户表` | + | 制单日期 | 日期时间 | `用户表` | + +- **跨字段规则**: - +- **边界**: 单页最大条数受限(默认 100);密码与敏感字段不返回;查询为只读,不产生写副作用 +- **验收**: 查询结果与库内数据一致;分页 / 排序 / 过滤参数生效;空结果返回空列表而非错误 +- **依赖表**: `tUser`(读)、`tStaff`(读,员工名 / 部门显示来源) +- **依赖接口**: — diff --git a/docs/01-需求清单/USR-用户管理/REQ-USR-004.md b/docs/01-需求清单/USR-用户管理/REQ-USR-004.md new file mode 100644 index 0000000..9f3a3cb --- /dev/null +++ b/docs/01-需求清单/USR-用户管理/REQ-USR-004.md @@ -0,0 +1,21 @@ +### REQ-USR-004 用户登录 + +**目标**: 用户使用账号密码完成身份认证并获取访问凭证 + +- **输入**: + + - **表1**: + + | 字段 | 类型 | 必填 | 输入方式 | 显示来源 | 默认值 | 业务规则 | + | --- | ---- | --- | ---- | ------- | --- | ------------------- | + | 用户名 | 文本 | 是 | 手工输入 | — | — | - | + | 密码 | 文本 | 是 | 手工输入 | — | — | 输入显示星号 | + | 版本 | 文本 | 是 | 下拉单选 | 标准版/- | 标准版 | | + +- **输出**: 成功/失败 + +- **跨字段规则**: 校验用户名 + 密码哈希;连续失败达到阈值临时锁定账号;登录成功签发限时 token 并返回基本用户信息 +- **边界**: token 设置合理过期时间;接口需具备防暴力破解保护 +- **验收**: 正确凭据返回 token + 用户基本信息;错误凭据返回明确错误码;账号锁定状态返回剩余冷却时间 +- **依赖表**: `tUser`(读 + 写 `tLastLoginDate`);登录失败计数走 Redis(不入 DB) +- **依赖接口**: — diff --git a/docs/01-需求清单/USR-用户管理/_module.md b/docs/01-需求清单/USR-用户管理/_module.md new file mode 100644 index 0000000..b8d0294 --- /dev/null +++ b/docs/01-需求清单/USR-用户管理/_module.md @@ -0,0 +1,5 @@ +# USR-用户管理 + +- **模块简述**: 维护系统用户的基本信息及登录认证,支持用户的增加、修改、查询和登录 +- **依赖模块**: — +- **涉及表**: `tUser`、`tStaff`、`tPermissionCategory`、`tUserPermission` diff --git a/docs/01-需求清单/index.md b/docs/01-需求清单/index.md new file mode 100644 index 0000000..3eae45d --- /dev/null +++ b/docs/01-需求清单/index.md @@ -0,0 +1,18 @@ +# 需求清单 + +> 本目录按模块组织所有功能需求。每个模块一个子目录,含 `_module.md`(模块头)和 `REQ-XXX-NNN.md`(每张 REQ 卡片一个文件)。下方核心功能点供 CC 拆分出 REQ 编号 + 标题 + 草拟规则;卡片内输入 / 输出的简述句和 N 张字段表由人工编辑。 + +## 模块索引 + + +| 模块代码 | 模块名称 | 核心功能点(简要) | +| ---- | ---- | ------------------- | +| USR | 用户管理 | 增加用户,修改用户,查询用户,登录用户 | +| MOD | 模块管理 | 增加模块,修改模块,删除模块,查询模块 | + + +## 填写说明 + +1. 每个模块占一行,`模块代码` 用大写英文缩写(如 SYS / PUR / INV / SAL / FIN / HR) +2. `核心功能点` 只需列关键词,CC 会基于此拆分出 N 张 REQ 卡片骨架(卡片内输入 / 输出的简述句和字段表仍由人工编辑) +3. 填完后运行 `/erp-workflow:plan-start`,CC 会自动检测并进入需求生成阶段 diff --git a/docs/02-开发计划.md b/docs/02-开发计划.md new file mode 100644 index 0000000..ae14dab --- /dev/null +++ b/docs/02-开发计划.md @@ -0,0 +1,31 @@ +# 02-开发计划 + +## 一、模块依赖表 + +| 模块 ID | 模块名 | 依赖模块 | 依赖表 | +|---|---|---|---| +| module_mod | 模块管理 | — | `tModule` | +| module_usr | 用户管理 | — | `tUser`、`tStaff`、`tPermissionCategory`、`tUserPermission` | + +## 二、开发顺序清单(CC 分发权威) + +> 本清单由 A5 `downstream-gen` 一次性生成。**每行是一个 REQ**,不是模块。CC 按表格行序从上到下扫描,对每个 REQ 所属模块查 `docs/08 § 二` 的 `MR:` 字段 + GitLab API `state`:`merged` 跳过,其他(`—` / opened / closed / 查不到)选为当前模块;`module-start` 会把该模块的所有 REQ 一次做完。 +> +> **约束**:同一模块的所有 REQ 必须**连续排列**。允许打破依赖拓扑(如环依赖、业务必须先做),但必须在「备注」列写明原因。 + +| # | REQ | 所属模块 | 选中理由 | 备注 | +|---|-----|---------|---------|------| +| 1 | **REQ-MOD-001** | module_mod | 所属模块无依赖,基础模块;新增是 CRUD 起点 | — | +| 2 | **REQ-MOD-002** | module_mod | 同模块内依赖 REQ-MOD-001 的写入数据 | — | +| 3 | **REQ-MOD-003** | module_mod | 同模块内依赖 REQ-MOD-001 的写入数据 | — | +| 4 | **REQ-MOD-004** | module_mod | 同模块只读,放最后便于覆盖前 3 个 REQ 写入的数据 | — | +| 5 | **REQ-USR-001** | module_usr | 所属模块无依赖;用户新增是用户域 CRUD 起点 | — | +| 6 | **REQ-USR-002** | module_usr | 同模块内依赖 REQ-USR-001 的写入数据 | — | +| 7 | **REQ-USR-003** | module_usr | 同模块只读,放在写操作之后,便于覆盖测试数据 | — | +| 8 | **REQ-USR-004** | module_usr | 登录依赖 REQ-USR-001 创建的账号;放本模块末尾 | — | + +## 三、关键说明 + +- 模块顺序按字母序(MOD → USR),两模块无相互依赖,顺序可调。 +- USR 模块「涉及表」中的 `tStaff` / `tPermissionCategory` 仅作为下拉数据源被 REQ-USR-001/002 读取;本期未拆出独立 REQ,由 USR 模块内的种子数据脚本(B 阶段任意 REQ 的 spec 中确定)填充。 +- 软删除(`bDeleted`)字段已在 V1 schema 中预置,所有「删除 / 查询」类 REQ 默认按 `bDeleted = 0` 过滤。 diff --git a/docs/03-数据库设计文档.md b/docs/03-数据库设计文档.md new file mode 100644 index 0000000..fe53b37 --- /dev/null +++ b/docs/03-数据库设计文档.md @@ -0,0 +1,231 @@ +# 03-数据库设计文档 + +Schema: `xlyweberp_vibe_erp_test` +Migration 清单: `sql/migrations/V*.sql`(由 Flyway 顺序 apply) +生成方式: 由 A3 `db-design-gen` 基于 `docs/01-需求清单//REQ-*.md` REQ 卡片正向设计生成(schema SSoT)。 + +## 项目标准列约定 + +下文每张业务表的字段清单都自动包含以下 5 个标准列(匈牙利前缀 `i` int / `s` varchar / `t` datetime)。渲染时由 `docs-03-table-template.md` 模板内置原样输出。 + +| 列名 | 类型 | 可空 | 主键 | 说明 | +|---|---|---|---|---| +| `iIncrement` | int | 否 | 是 | 整数主键 ID(自增方式由实现决定:DB `AUTO_INCREMENT` 或应用 / 触发器分配) | +| `sId` | varchar(100) | 是 | — | 业务 ID(对外暴露的字符串标识,如 UUID / 人类可读编号) | +| `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离) | +| `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离) | +| `tCreateDate` | datetime | 否 | — | 记录创建时间 | + +字典 / 辅助表如有豁免,在该表业务注记里注明豁免原因。 + +## ER 关系概览 + +本期共 5 张业务表,分布在 USR / MOD 两个模块: + +- **`tUser`** 是用户账户主表,可选关联 `tStaff`(员工);与 `tPermissionCategory` 通过 `tUserPermission` 形成多对多权限授权关系。登录失败计数走 Redis,不入库。 +- **`tStaff`** 是职员维度表,作为 `tUser` 的员工来源(员工名 / 部门下拉)。 +- **`tPermissionCategory`** 是权限分类树(自引用 `iParentId`),由 `tUserPermission` 关联到具体用户。 +- **`tUserPermission`** 是 `tUser` × `tPermissionCategory` 的关联表(多对多)。 +- **`tModule`** 是 ERP 业务模块定义表(自引用 `iParentId` 形成模块树),与本期其他表无外键关系。 + +软删除统一使用 `bDeleted` / `tDeletedDate` / `sDeletedBy` 三件套;查询接口默认过滤 `bDeleted = 0`。 + +## 表清单 + +- `tUser` — 系统用户账户与登录凭据 +- `tStaff` — 职员维度(员工名 / 部门 / 编号) +- `tPermissionCategory` — 权限分类树 +- `tUserPermission` — 用户与权限分类的关联 +- `tModule` — ERP 业务模块元数据树 + +--- + +## `tUser` — 系统用户账户与登录凭据 + +### 字段 + +| 字段 | 类型 | Nullable | 默认 | 业务含义 | +|---|---|---|---|---| +| `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | +| `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | +| `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | +| `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | +| `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | +| `sUserNo` | varchar(50) | 否 | — | 用户号;系统内唯一 | +| `sUserName` | varchar(50) | 否 | — | 用户名(登录账号);系统内唯一 | +| `iStaffId` | int | 是 | NULL | 关联职员 ID(可选,外键 → `tStaff.iIncrement`) | +| `sUserType` | varchar(20) | 否 | `普通用户` | 用户类型;枚举:`普通用户` / `超级管理员` | +| `sLanguage` | varchar(10) | 否 | `zh` | 语言偏好;枚举:`zh` / `en` / `zh-TW` | +| `bCanModifyDocs` | tinyint(1) | 否 | 0 | 单据修改权限;0 否 / 1 是 | +| `sPasswordHash` | varchar(255) | 否 | — | 密码哈希值(BCrypt 等强哈希算法),新增默认初始密码 `666666` 的哈希 | +| `tLastLoginDate` | datetime | 是 | NULL | 最后登录时间 | +| `sCreatedBy` | varchar(50) | 是 | — | 制单人(创建用户的操作员用户号) | +| `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记;0 有效 / 1 已作废 | +| `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | +| `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | + +### 索引 + +- `uk_user_no` (UNIQUE): (`sUserNo`) +- `uk_user_name` (UNIQUE): (`sUserName`) +- `idx_staff_id` (NORMAL): (`iStaffId`) +- `idx_brand_subsidiary` (NORMAL): (`sBrandsId`, `sSubsidiaryId`) +- `idx_deleted_login` (NORMAL): (`bDeleted`, `tLastLoginDate`) + +### 外键 + +- `fk_user_staff`: `iStaffId` → `tStaff.iIncrement` (ON DELETE SET NULL, ON UPDATE CASCADE) + +### 业务注记 + +- 用户名 / 用户号在系统内全局唯一(含已软删除记录是否计入唯一性,需在 service 层用部分唯一索引或代码校验决定,本设计取代码校验,唯一索引仅约束未删除部分由应用层保证)。 +- 密码哈希存储;登录失败次数 / 临时锁定不入库,由 Redis 维护。 +- REQ-USR-003 查询接口的「作废」字段直接映射 `bDeleted`;「制单日期」即 `tCreateDate`;「制单人」即 `sCreatedBy`。 +- 未关联职员的用户允许 `iStaffId = NULL`(如系统管理员账号)。 + +--- + +## `tStaff` — 职员维度(员工名 / 部门 / 编号) + +### 字段 + +| 字段 | 类型 | Nullable | 默认 | 业务含义 | +|---|---|---|---|---| +| `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | +| `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | +| `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | +| `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | +| `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | +| `sStaffNo` | varchar(50) | 是 | — | 职员编号;系统内唯一 | +| `sStaffName` | varchar(50) | 否 | — | 职员姓名 | +| `sDepartment` | varchar(100) | 是 | NULL | 所属部门(本期暂用字符串,未来如需独立 `tDepartment` 字典表再另行重构) | +| `sCreatedBy` | varchar(50) | 是 | — | 制单人 | +| `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记 | +| `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | +| `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | + +### 索引 + +- `uk_staff_no` (UNIQUE): (`sStaffNo`) +- `idx_staff_name` (NORMAL): (`sStaffName`) +- `idx_department` (NORMAL): (`sDepartment`) + +### 外键 + +(无) + +### 业务注记 + +- USR 模块通过 `tUser.iStaffId` 引用本表;REQ-USR-003 列表的「员工名 / 部门」均来自本表。 +- 部门当前以字符串保存,便于本期快速落地;后续若需独立部门字典表(如审批流引用部门),改为 `iDepartmentId` 外键。 + +--- + +## `tPermissionCategory` — 权限分类树 + +### 字段 + +| 字段 | 类型 | Nullable | 默认 | 业务含义 | +|---|---|---|---|---| +| `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | +| `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | +| `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | +| `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | +| `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | +| `sCategoryCode` | varchar(50) | 否 | — | 权限分类编码;系统内唯一 | +| `sCategoryName` | varchar(100) | 否 | — | 权限分类名称(界面展示) | +| `iParentId` | int | 是 | NULL | 父分类 ID(自引用,根节点为 NULL) | +| `iSortOrder` | int | 否 | 0 | 同级排序号 | +| `sCreatedBy` | varchar(50) | 是 | — | 制单人 | +| `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记 | +| `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | +| `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | + +### 索引 + +- `uk_category_code` (UNIQUE): (`sCategoryCode`) +- `idx_parent` (NORMAL): (`iParentId`) + +### 外键 + +- `fk_category_parent`: `iParentId` → `tPermissionCategory.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) + +### 业务注记 + +- REQ-USR-001 / 002 表 2「权限组 - 权限分类」下拉来源即本表(`bDeleted = 0` 过滤)。 +- 自引用形成权限分类树;删除前须确保无子分类、无 `tUserPermission` 引用。 + +--- + +## `tUserPermission` — 用户与权限分类关联 + +### 字段 + +| 字段 | 类型 | Nullable | 默认 | 业务含义 | +|---|---|---|---|---| +| `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | +| `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | +| `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | +| `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | +| `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | +| `iUserId` | int | 否 | — | 关联用户 ID(外键 → `tUser.iIncrement`) | +| `iCategoryId` | int | 否 | — | 关联权限分类 ID(外键 → `tPermissionCategory.iIncrement`) | +| `sCreatedBy` | varchar(50) | 是 | — | 授权操作人 | + +### 索引 + +- `uk_user_category` (UNIQUE): (`iUserId`, `iCategoryId`) +- `idx_category` (NORMAL): (`iCategoryId`) + +### 外键 + +- `fk_up_user`: `iUserId` → `tUser.iIncrement` (ON DELETE CASCADE, ON UPDATE CASCADE) +- `fk_up_category`: `iCategoryId` → `tPermissionCategory.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) + +### 业务注记 + +- 关联表保留标准列以保持设计一致性,无独立软删除字段——授权撤销直接物理删除关联行(CASCADE 也会随用户删除而清理)。 +- REQ-USR-001 / 002 提交时按表 2 选中行重建本表 `iUserId` 下的关联(先删后插或差异同步)。 + +--- + +## `tModule` — ERP 业务模块元数据树 + +### 字段 + +| 字段 | 类型 | Nullable | 默认 | 业务含义 | +|---|---|---|---|---| +| `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | +| `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | +| `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | +| `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | +| `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | +| `sDisplayType` | varchar(20) | 否 | `手机端` | 显示类型;枚举:`手机端` / `前端业务` / `系统配置` / `接口` | +| `sProcedureName` | varchar(100) | 否 | — | 存储过程(审核)名称;系统内唯一 | +| `sModuleType` | varchar(50) | 否 | — | 模块类型(本期按自由文本处理,VARCHAR(50);如未来收敛到枚举再加 CHECK 约束) | +| `sManageDeptEn` | varchar(50) | 否 | — | 管理部门英文标识 | +| `bShowPermission` | tinyint(1) | 否 | 0 | 权限是否显示;0 否 / 1 是 | +| `sModuleNameZh` | varchar(100) | 否 | — | 界面名称(中文,模糊查询用) | +| `iParentId` | int | 是 | NULL | 父模块 ID(自引用,根节点为 NULL) | +| `iSortOrder` | int | 否 | 0 | 同级排序号 | +| `sCreatedBy` | varchar(50) | 是 | — | 制单人 | +| `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记 | +| `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | +| `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | + +### 索引 + +- `uk_procedure_name` (UNIQUE): (`sProcedureName`) +- `idx_module_name_zh` (NORMAL): (`sModuleNameZh`) +- `idx_parent` (NORMAL): (`iParentId`) +- `idx_display_type` (NORMAL): (`sDisplayType`) + +### 外键 + +- `fk_module_parent`: `iParentId` → `tModule.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) + +### 业务注记 + +- REQ-MOD-004 查询按 `sModuleNameZh` 模糊匹配(`LIKE '%关键字%'`,`bDeleted = 0` 过滤),结果按 `iParentId` 拼装树形。 +- REQ-MOD-003 删除策略:仅软删除(写入 `bDeleted` / `tDeletedDate` / `sDeletedBy`);service 层先校验「无未删除子模块」「未被外部业务引用」再执行。 +- `sProcedureName` 假定系统内唯一,若实际允许同名请在审阅时移除该唯一索引。 diff --git a/docs/04-技术规范.md b/docs/04-技术规范.md new file mode 100644 index 0000000..c70ccdc --- /dev/null +++ b/docs/04-技术规范.md @@ -0,0 +1,157 @@ +# 04-技术规范 + +## 零、技术栈总览 + +| 分层模块 | 技术 | 版本要求 | 说明 | +|---|---|---|---| +| 前端基础框架 | React | 18.x | 构建前端应用 | +| 前端 UI 组件 | Ant Design | 5.x | 页面组件与交互控件 | +| 前端状态管理 | Redux Toolkit | 最新稳定版 | 管理全局状态 | +| 前端路由管理 | React Router | v6 | 页面路由与导航 | +| 前端工程化构建 | Vite | 最新稳定版 | 前端开发与打包构建 | +| 前端接口通信 | Axios | 最新稳定版 | 调用后端 API | +| 后端基础框架 | Spring Boot | 3.x | 构建后端服务 | +| 后端数据访问 | MyBatis-Plus | 最新稳定版 | 数据库访问与 ORM 增强 | +| 工作流引擎 | Activiti | 6.x | 审批流、流程流转 | +| 缓存服务 | Redis | 最新稳定版 | 缓存、会话、分布式能力 | +| 报表打印 | JXLS | 2.8.1 | 基于 Excel 模板生成报表 | +| Excel 导入导出 | EasyExcel | 4.0.3 | Excel 数据导入导出 | +| 关系型数据库 | MySQL | 8.x | 核心业务数据存储 | +| 数据库 schema 迁移 | Flyway (`flyway-core` + `flyway-mysql`) | 10.x / 最新稳定版 | `sql/migrations/V_n__*.sql` 顺序 apply;Spring Boot 启动时自动应用 | +| 接口风格 | RESTful API | 统一规范 | 前后端接口设计规范 | +| 权限认证 | Spring Security / JWT | 最新稳定版 | 登录认证、权限控制 | +| API 文档 | OpenAPI / Swagger | 最新稳定版 | 接口文档与调试 | +| 项目构建管理 | Maven | 3.9.x | Java 项目依赖与构建 | +| JDK 运行环境 | Java | 17 / 21 | Spring Boot 3 推荐版本 | +| 部署容器 | Docker | 最新稳定版 | 容器化部署 | +| Web 服务器 / 反向代理 | Nginx | 最新稳定版 | 前端托管、反向代理、负载分发 | +| 日志管理 | Logback | 默认集成 / 最新稳定版 | 应用日志输出 | +| 对象映射工具 | MapStruct | 最新稳定版 | DTO / VO / Entity 转换 | +| 工具类库 | Hutool / Apache Commons | 最新稳定版 | 常用工具方法支持 | + +> 本表由 scope-lock 锁定。后续所有规范基于此表推导。 + +## 一、后端规范 + +### 1.1 分层结构 + +| 层 | 职责 | +|---|---| +| `controller` | 接收 HTTP 请求,参数校验,调用 service,返回统一响应 | +| `service` | 业务逻辑编排,事务边界;接口与实现分离 | +| `mapper` | 数据访问层(MyBatis-Plus),单表 CRUD + 自定义 SQL | +| `entity` | 与表 1:1 映射的 PO | +| `dto` | 入参对象(接口入参) | +| `vo` | 出参对象(接口响应) | + +### 1.2 命名约定 + +- **包名**:全小写,根包 `com.xly.erp`,子包按业务模块代码小写(如 `module.usr`) +- **类名**:UpperCamelCase;Controller 后缀 `Controller`,Service 接口无后缀、实现类后缀 `Impl`,Mapper 后缀 `Mapper`,实体后缀 `Entity` 可省略 +- **方法名**:lowerCamelCase;CRUD 动词:`create / update / removeById / getById / page / list` +- **常量**:全大写下划线,如 `MAX_LOGIN_ATTEMPTS` + +示例 1:`com.example.erp.module.usr.controller.UserController` +示例 2:`com.example.erp.module.mod.service.impl.ModuleServiceImpl` + +### 1.3 统一响应格式 + +所有接口返回 `Result`: + +```json +// 成功 +{ "code": 0, "msg": "ok", "data": { /* 业务数据 */ } } +// 失败 +{ "code": 40001, "msg": "用户名或密码错误", "data": null } +``` + +错误码段位划分: +- `0`:成功 +- `1xxxx`:参数校验失败 +- `2xxxx`:认证 / 鉴权失败 +- `3xxxx`:业务规则失败 +- `5xxxx`:系统内部错误 + +### 1.4 异常处理 + +- 全局 `@RestControllerAdvice` 拦截所有 Controller 抛出的异常 +- 业务异常用自定义 `BizException(code, msg)`,由全局处理器转为标准 `Result` +- 参数校验异常(`MethodArgumentNotValidException`)统一返回 `1xxxx` 错误码 +- **接口响应禁止回显后端异常堆栈**——返回用户友好错误码 + 文案,堆栈只记日志 +- 不要在 controller / service 里 catch 后吞异常,必须向上抛或显式转 `BizException` + +### 1.5 事务 + +- 事务边界统一在 `service` 实现类,使用 `@Transactional(rollbackFor = Exception.class)` +- controller / mapper 层禁止开事务 +- 跨服务调用(远程 RPC / HTTP)禁止包在事务里;如需保证最终一致性走消息或补偿,不依赖数据库事务 + +### 1.6 认证 + +- 登录使用用户名 + 密码,后端签发 JWT(HS256),写入响应 body +- Token 生命周期:access token 8 小时;引入 refresh token(30 天)支持刷新 +- 密钥放 `.env.local` 的 `JWT_SECRET`,禁止入仓 +- 受保护接口由 Spring Security `JwtAuthenticationFilter` 校验;未携带或过期返回 `2xxxx` + +## 二、前端规范 + +### 2.1 目录约定 + +| 目录 | 职责 | +|---|---| +| `api/` | HTTP 请求封装;每模块一文件;**前端禁止直接写 SQL / 操作 DB**,所有数据访问走此层 | +| `components/` | 通用展示组件(无业务语义) | +| `pages/` | 按模块分子目录,每 REQ 一页面 | +| `store/` | Redux Toolkit slices;只放跨页面共享状态 | +| `hooks/` | 自定义 hooks,如 `useUser` / `usePagination` | +| `utils/` | 工具函数(日期、金额、权限) | +| `router/` | 路由配置 | + +### 2.2 状态管理 + +- **服务端数据**:每个页面独立请求 + 局部 `useState`,不进 Redux +- **跨页面共享**:登录用户、权限、模块树 等放 Redux Toolkit +- **表单状态**:使用 Ant Design `Form.useForm`,不进 Redux + +### 2.3 请求封装 + +- 统一 axios 实例,配置:`baseURL=/api`、超时 15s、自动注入 `Authorization: Bearer ` +- 响应拦截器:`code !== 0` 触发统一错误处理(`message.error(msg)` + 抛错),`401` 跳登录 +- 不在业务代码里手动设置请求头 + +### 2.4 错误处理 + +- 网络错误:拦截器统一 `message.error('网络异常')` +- 业务错误(`code !== 0`):拦截器读 `msg` 字段提示,业务代码可 catch 自定义补充 +- 页面级错误(路由错误 / 渲染异常):`ErrorBoundary` 包裹,展示 `Result` 组件 + +## 三、共同约定 + +### 3.1 Git 提交 + +`(): REQ-XXX-NNN` + +业务类(feat / fix / test)必须带 `REQ-XXX-NNN` 后缀。 + +### 3.2 分页查询 + +- **后端**:使用 MyBatis-Plus `Page`,请求入参 `pageNum`(1 起)+ `pageSize`(默认 20,上限 100);响应 `{ records, total, pageNum, pageSize }` +- **前端**:`Table` 配 `pagination` 配置,与后端字段一一对应 + +### 3.3 日期与金额 + +- **后端**:日期统一 `LocalDateTime`(无时区业务)/ `OffsetDateTime`(有时区);金额一律 `BigDecimal`,小数位精度由业务规则决定 +- **前端**:日期展示用 `dayjs`,统一格式 `YYYY-MM-DD HH:mm:ss`;金额展示保留 2 位小数 + 千分位 + +### 3.4 数据访问规约 + +- **SELECT 字段必须显式列举**,禁止 `SELECT *` +- 循环中**禁止**执行 DB 查询(N+1 反模式),改用批量 IN / JOIN / 一次查 Map 建索引 +- Mapper XML 字段名 / 表名通过 `` 片段或常量引用,避免散落字符串 +- 复杂查询用 MyBatis-Plus `LambdaQueryWrapper`;动态 SQL 用 XML + +### 3.5 配置与安全 + +- DB 连接 / Redis 地址 / JWT 密钥 / 第三方 URL 一律放 `application.yml` + `.env.local`,**代码里禁止硬编码** +- 前端 `localStorage` **禁止**存敏感信息(token / 身份证 / 个人数据),token 存内存 + refresh token 走 HttpOnly Cookie +- 接口响应禁止回显异常堆栈(与 § 1.4 一致) diff --git a/docs/05-API接口契约.md b/docs/05-API接口契约.md new file mode 100644 index 0000000..5845704 --- /dev/null +++ b/docs/05-API接口契约.md @@ -0,0 +1,165 @@ +# 05-API接口契约 + +BasePath: `/api` +端口: `8080` + +## 全局约定 + +### 响应格式 +```json +{"code": 200, "message": "操作成功", "data": {}, "timestamp": 1700000000000} +``` + +### 错误码 +| 范围 | 含义 | +|---|---| +| 200 | 成功 | +| 400xx | 客户端参数错误 | +| 401xx | 认证/授权错误 | +| 403xx | 权限不足 | +| 404xx | 资源不存在 | +| 500xx | 服务端内部错误 | + +### 鉴权 + +除 `POST /api/usr/auth/login` 外,所有接口必须在 HTTP 头携带: + +``` +Authorization: Bearer +``` + +后端由 `JwtAuthenticationFilter` 校验签名 + 过期时间;缺失或失效返回 `401xx`。 + +### 分页参数 + +列表查询统一接收 query 参数:`pageNum`(1 起,默认 1)、`pageSize`(默认 20,上限 100)。 +响应 `data` 字段结构: + +```json +{ "records": [], "total": 0, "pageNum": 1, "pageSize": 20 } +``` + +## 接口清单 + +(各模块接口段落见下方,由 `downstream-gen` 按 REQ 填入) + +--- + +## module_mod 模块管理 + +### REQ-MOD-001 模块新增 + +- **Method**: POST +- **Path**: `/api/mod/modules` +- **Auth**: 必需 +- **Permission**: 系统管理(仅超级管理员) +- **请求**: `CreateModuleDTO` —— `sDisplayType`、`sProcedureName`、`sModuleType`、`sManageDeptEn`、`bShowPermission`、`sModuleNameZh`、`iParentId?`、`iSortOrder?` +- **响应**: `data` = `{ "iIncrement": 123 }`(新模块 id) + +#### 错误码 +- `40001` — 必填字段缺失或类型错误(含字段定位) +- `40010` — `sDisplayType` 不在枚举范围 +- `40020` — `sProcedureName` 已存在(唯一冲突) +- `40021` — `iParentId` 指定的父模块不存在或已软删除 +- `40300` — 当前用户非超级管理员 + +### REQ-MOD-002 模块修改 + +- **Method**: PUT +- **Path**: `/api/mod/modules/{id}` +- **Auth**: 必需 +- **Permission**: 系统管理(仅超级管理员) +- **请求**: path `{id}` = `iIncrement`;body `UpdateModuleDTO` 字段同新增(除 `sProcedureName` 之外可改,`sProcedureName` 不可修改) +- **响应**: `data` = `{ "iIncrement": 123 }` + +#### 错误码 +- `40001` — 字段格式错误 +- `40021` — `iParentId` 形成环或指向自身 +- `40400` — 模块 id 不存在或已删除 + +### REQ-MOD-003 模块删除 + +- **Method**: DELETE +- **Path**: `/api/mod/modules/{id}` +- **Auth**: 必需 +- **Permission**: 系统管理(仅超级管理员) +- **请求**: path `{id}` = `iIncrement` +- **响应**: `data` = `null`(成功) + +#### 错误码 +- `40400` — 模块不存在 +- `40901` — 模块仍有未删除子节点 +- `40902` — 模块被外部业务引用(菜单 / 权限 / 角色等) + +### REQ-MOD-004 模块查询 + +- **Method**: GET +- **Path**: `/api/mod/modules` +- **Auth**: 必需 +- **Permission**: 所有登录用户 +- **请求**: query `keyword?`(对 `sModuleNameZh` 模糊匹配,空匹配全部) +- **响应**: `data` = 模块树数组:`[{ iIncrement, sModuleNameZh, sDisplayType, sManageDeptEn, iParentId, iSortOrder, children: [...] }]` + +#### 错误码 +- `40001` — `keyword` 长度超限 + +--- + +## module_usr 用户管理 + +### REQ-USR-001 用户新增 + +- **Method**: POST +- **Path**: `/api/usr/users` +- **Auth**: 必需 +- **Permission**: 用户管理(仅超级管理员) +- **请求**: `CreateUserDTO` —— `sUserNo`、`sUserName`、`iStaffId?`、`sUserType`、`sLanguage`、`bCanModifyDocs?`、`permissionCategoryIds[]`(权限组);密码后端按规则生成默认 `666666` 哈希 +- **响应**: `data` = `{ "iIncrement": 456, "sUserNo": "..." }` + +#### 错误码 +- `40001` — 字段格式错误 +- `40020` — `sUserName` 或 `sUserNo` 已存在 +- `40022` — `iStaffId` 不存在 +- `40023` — `permissionCategoryIds` 中含无效分类 id + +### REQ-USR-002 用户修改 + +- **Method**: PUT +- **Path**: `/api/usr/users/{id}` +- **Auth**: 必需 +- **Permission**: 用户管理(仅超级管理员;密码不在此接口修改) +- **请求**: path `{id}` = `iIncrement`;body `UpdateUserDTO` 字段同新增(不含密码);`permissionCategoryIds[]` 重建权限组 +- **响应**: `data` = `{ "iIncrement": 456 }` + +#### 错误码 +- `40001` — 字段格式错误 +- `40020` — 用户名 / 用户号唯一冲突 +- `40400` — 用户 id 不存在 + +### REQ-USR-003 用户查询 + +- **Method**: GET +- **Path**: `/api/usr/users` +- **Auth**: 必需 +- **Permission**: 用户管理 / 本人查询 +- **请求**: query `field`(用户名 / 员工名 / 用户号 / 部门 / 用户类型 / 作废 / 登录日期 / 制单人)、`match`(包含 / 不包含 / 等于)、`value?`、`pageNum?`、`pageSize?` +- **响应**: 分页对象,`records[]` 字段:`iIncrement`、`sUserName`、员工名、`sUserNo`、部门、`sUserType`、`sLanguage`、`bDeleted`、`tLastLoginDate`、`sCreatedBy`、`tCreateDate`(密码字段不返回) + +#### 错误码 +- `40001` — `field` / `match` 取值非法 +- `40002` — `pageSize` 超过 100 + +### REQ-USR-004 用户登录 + +- **Method**: POST +- **Path**: `/api/usr/auth/login` +- **Auth**: 无(公开) +- **Permission**: — +- **请求**: `LoginDTO` —— `sUserName`、`password`、`version`(标准版 / -) +- **响应**: `data` = `{ "accessToken": "", "refreshToken": "", "expiresIn": 28800, "user": { "iIncrement", "sUserNo", "sUserName", "sUserType", "sLanguage" } }` + +#### 错误码 +- `40001` — 用户名 / 密码字段为空 +- `40101` — 用户名或密码错误 +- `40102` — 账号已禁用(`bDeleted = 1`) +- `42301` — 账号临时锁定(连续失败超过阈值),`message` 含剩余冷却秒数 diff --git a/docs/06-UI交互规范.md b/docs/06-UI交互规范.md new file mode 100644 index 0000000..54588e3 --- /dev/null +++ b/docs/06-UI交互规范.md @@ -0,0 +1,96 @@ +# 06-UI交互规范 + +## 一、整体布局 + +### 1.1 页面框架 + +采用 Ant Design `Layout` 组合骨架:顶部 `Header` 放 logo / 全局菜单 / 用户信息;左侧 `Sider` 放可折叠的多级菜单(通过 `Menu` 组件渲染,菜单项数据由后端模块树接口返回);右侧 `Content` 放业务内容区,顶部为面包屑(`Breadcrumb`),下方为页面主体。整体根节点用 `ConfigProvider` 注入主题与中文 `locale`。 + +### 1.2 布局参数 + +| 参数 | 默认值 | 说明 | +|---|---|---| +| Header 高度 | 56 px | 固定置顶,z-index 高于 Content | +| Sider 展开宽度 | 224 px | 多级菜单展开时 | +| Sider 折叠宽度 | 64 px | 仅显示 Icon | +| Content 内边距 | 16 px | 上下左右 | +| 最小分辨率 | 1280 × 720 | ERP 桌面端为主,不做 H5 适配 | + +## 二、标准页面类型 + +ERP 业务以 CRUD 为主,统一为 3 类标准页:列表页、表单页、详情页。模块管理因含树形结构,额外保留树形管理页。 + +### 2.1 列表页 + +固定布局:`PageHeader` 标题区 → 顶部操作区("新建"等主按钮 + 批量操作) → 搜索栏(`Form` 折叠展开) → 数据表格(`Table` + 行操作列) → 底部分页(`Pagination`,默认每页 20 条,可选 10 / 20 / 50 / 100)。 + +### 2.2 表单页 + +新增 / 编辑统一用 `Drawer`(从右侧滑出,宽度 520 px)承载,避免页面跳转打断列表上下文。校验时机:失焦校验 + 提交前完整校验(`Form.useForm` + `rules`)。提交按钮固定在 Drawer 底部,左侧"取消"右侧"确定"。 + +### 2.3 详情页 + +独立路由页面,顶部用 `Descriptions` 展示基本信息(2 列布局),下方用 `Tabs` 切换"基本信息 / 关联记录 / 操作日志"等分组。详情页只读,编辑跳回列表页 Drawer。 + +### 2.4 树形管理页 + +模块管理使用:左侧 `Tree` 展示模块层级(含搜索框),右侧根据选中节点展示详情/编辑表单。新增子节点通过节点上的"+"按钮触发,删除走二次确认。 + +## 三、通用交互规则 + +### 3.1 操作反馈 + +- 成功:`message.success`,2 秒自动消失 +- 失败 / 业务错误:`message.error`,展示后端 `msg` 字段 +- 危险操作(删除 / 禁用 / 重置密码):`Modal.confirm` 二次确认,确认按钮 `danger` +- 长耗时按钮:进入请求即 `loading=true`,请求完成(成功或失败)才解除 + +### 3.2 数据展示 + +- 空状态:`Empty`,附主操作按钮(如"新建第一条") +- 加载:`Spin` 包裹内容区,最小展示 300 ms 避免闪烁 +- 异常:网络/服务异常用 `Result` 组件,附"重试"按钮 + +### 3.3 权限控制(前端) + +- 菜单级:登录后调 `/auth/menu` 拉模块树,前端按返回数据渲染 `Menu` +- 按钮级:组件读取 `useUser().permissions` 判断操作按钮显隐 +- 路由级:`PrivateRoute` 高阶组件包装受保护路由,未登录或无权限重定向至 `/403` +- 所有权限规则与后端 RBAC 保持一致,前端不做"最终判定",只做"友好屏蔽",后端依然校验 + +## 四、主题与颜色 + +基于 Ant Design 5 的 design token 体系,使用 `ConfigProvider.theme` 全局注入: + +| Token | 默认值 | 说明 | +|---|---|---| +| colorPrimary | #1677ff | 主色(按钮、链接、选中态) | +| colorSuccess | #52c41a | 成功反馈 | +| colorWarning | #faad14 | 警告反馈 | +| colorError | #ff4d4f | 错误反馈、危险操作 | +| borderRadius | 4 | 全局圆角 | +| fontSize | 14 | 默认字号 | + +## 五、页面清单 + +### module_mod 模块管理 + +- **模块管理树** (`/sys/modules`) + - 类型: 树形管理页 + - 对应 REQ: REQ-MOD-001 / REQ-MOD-002 / REQ-MOD-003 / REQ-MOD-004 + - 入口菜单: 系统设置 → 模块管理 + - 主要交互: 左侧模块树(搜索框 + 树节点) + 右侧 Drawer 表单(新增 / 编辑);节点上"+"新增子模块、删除走二次确认;REQ-MOD-004 的查询关键字直接绑定左侧树搜索框 + +### module_usr 用户管理 + +- **用户列表页** (`/sys/users`) + - 类型: 列表页 + - 对应 REQ: REQ-USR-001 / REQ-USR-002 / REQ-USR-003 + - 入口菜单: 系统设置 → 用户管理 + - 主要交互: 顶部搜索栏(查询字段 + 匹配方式 + 查询值) + Table(含序号 / 用户名 / 员工名 / 用户号 / 部门 / 用户类型 / 语言 / 作废 / 登录日期 / 制单人 / 制单日期 / 操作列) + 分页;新建 / 编辑用 Drawer,权限组用 Checkbox 表格选择 + +- **登录页** (`/login`) + - 类型: 表单页 + - 对应 REQ: REQ-USR-004 + - 入口菜单: 未登录默认重定向至此 + - 主要交互: 用户名 + 密码 + 版本(下拉,默认"标准版");提交后调 `POST /api/usr/auth/login`,成功跳转主页,账号锁定时展示剩余冷却时间 diff --git a/docs/07-环境配置.md b/docs/07-环境配置.md new file mode 100644 index 0000000..106b2c9 --- /dev/null +++ b/docs/07-环境配置.md @@ -0,0 +1,51 @@ +# 07-环境配置 + +## 一、依赖清单 + +| 层 | 依赖 | 版本 | 说明 | +|---|---|---|---| +| 运行时 | JDK | 17 或 21 | Spring Boot 3 推荐 | +| 运行时 | Node.js | 20 LTS | 前端构建与开发 | +| 运行时 | MySQL | 8.x | 业务数据库 | +| 运行时 | Redis | 最新稳定版 | 缓存、会话 | +| 构建 | Maven | 3.9.x | Java 后端构建 | +| 构建 | npm(随 Node 安装) | 10.x | 前端包管理 | +| 构建 | Vite | 最新稳定版 | 前端打包构建 | +| 框架 | Spring Boot | 3.x | 后端基础框架 | +| 框架 | MyBatis-Plus | 最新稳定版 | ORM | +| 框架 | Spring Security + JWT | 最新稳定版 | 认证授权 | +| 框架 | Activiti | 6.x | 工作流 | +| 框架 | Flyway (`flyway-core` + `flyway-mysql`) | 10.x / 最新稳定版 | 数据库迁移 | +| 框架 | React + Ant Design 5 + Redux Toolkit + React Router v6 + Axios | 见 docs/04 § 零 | 前端 | +| 容器 | Docker | 最新稳定版 | 部署 | +| 容器 | Nginx | 最新稳定版 | 静态托管 + 反向代理 | +| CLI 工具 | git | 任意 | 版本控制 | +| CLI 工具 | mysql 客户端 | 与服务端兼容 | 本地连库调试 | + +## 二、端口约定 + +| 服务 | 端口 | 说明 | +|---|---|---| +| 后端 HTTP | 8080 | Spring Boot 默认端口 | +| 前端 dev server | 5173 | Vite 默认端口 | +| MySQL | 3306 | 业务库 + 测试库 | +| Redis | 6379 | 默认端口 | +| Nginx | 80 / 443 | 反向代理(生产) | + +## 三、环境变量 + +运行时凭据(数据库连接、JWT 密钥等)全部放在仓库根的 `.env.local`,不入 git。 +字段清单与占位符见该文件,真实值由开发者本地填写。 + +## 四、常用命令 + +| 命令 | 说明 | +|---|---| +| `cd backend && mvn spring-boot:run` | 启动后端(dev profile) | +| `cd frontend && npm install && npm run dev` | 启动前端 dev server | +| `cd backend && mvn clean package` | 后端打包 | +| `cd frontend && npm run build` | 前端打包到 `dist/` | +| `bash scripts/test.sh` | 全量测试(lint + unit + integration + e2e) | +| `bash scripts/setup-test-db.sh` | DROP+CREATE 测试库(保留 schema 由 Flyway 启动时 apply) | +| `git push origin ` | 推送(pre-push hook 触发本地全量测试闸门) | +| `glab mr create -s -b master --fill` | 创建 GitLab MR(由 mr-create skill 调用) | diff --git a/docs/08-模块任务管理.md b/docs/08-模块任务管理.md new file mode 100644 index 0000000..40d677c --- /dev/null +++ b/docs/08-模块任务管理.md @@ -0,0 +1,76 @@ +# 08-工作流进度 + +> 全流程进度跟踪。CC 每完成一项产出就勾选一项。 +> - **§ 一 Plan(A0~A5)**:`plan-start` 找第一个未勾 A 子项分发到对应 skill +> - **§ 二 Coding(模块)**:分发以 `docs/02-开发计划.md § 二 开发顺序清单` 为准;`coding-start` 按 docs/02 顺序扫描,对每个 REQ 所属模块查询本 § 二的 `MR:` 字段 + GitLab API `state`,找第一个非 merged 模块分发。本 § 二 行序无语义,仅作模块元数据表 + +## 一、Plan 阶段(一次性) + +- [x] A0 项目初始化 — project-init + - [x] 依赖检查通过 + - [x] 项目文件骨架已创建(CLAUDE.md + docs/01-需求清单/index.md + docs/04-技术规范.md) + - [x] Git 已初始化 + +- [x] A1 范围锁定 — scope-lock + - [x] 项目概述已填写(CLAUDE.md § 🎯 项目概述) + - [x] 技术栈已确认(docs/04 § 零) + - [x] 需求清单索引已填写(docs/01-需求清单/index.md) + - [x] REQ 卡片骨架已生成(docs/01-需求清单//REQ-*.md,业务内容留待人工填写) + +- [x] A2 骨架生成 — skeleton-gen + - [x] 架构文档已生成(docs/04 § 一+、docs/06、docs/07、docs/09) + - [x] 工具脚本已生成(scripts/*.sh、.githooks/pre-push、.env.local) + - [x] .gitignore 已配置 + +- [x] A3 DB 设计 + REQ 回填 — db-design-gen + - [x] docs/03-数据库设计文档.md 已生成 + - [x] docs/01 各 REQ 卡片"依赖表" + 模块头"涉及表" 已回填 + +- [x] A4 DB 初始化 — db-init + - [x] sql/migrations/V1__initial_schema.sql 已生成 + - [x] DDL 与 docs/03 全量一致 + - [x] .env.local 凭据已验证(mysql -e "SELECT 1" OK) + - [x] setup-test-db.sh 防护通过 + DROP+CREATE + apply V1 已执行 + - [x] SHOW TABLES 行数 == docs/03 表数量 + +- [x] A5 下游文档生成 — downstream-gen + - [x] docs/02 开发计划已生成 + - [x] docs/05 API 契约已生成 + - [x] docs/06 § 五 页面清单已填入 + - [x] docs/10 验收清单已生成 + - [x] 下方模块列表已填入 + - [x] REQ 卡片依赖接口已回填 + +## 二、Coding 阶段(按模块循环) + +(A5 填入后,每行一个模块。每个模块的 `MR:` 字段在 `—` 和 `!` 之间变化,完成由 GitLab API `state=merged` 判定。`coding-start` 每次按 docs/02 REQ 序扫每模块的 MR state 决定派发。) + + + +- module_mod 模块管理 + - 依赖: — + - 路径: backend/module/mod/, frontend/pages/mod/ + - MR: — + - 功能: + - [ ] REQ-MOD-001 模块新增 + - [ ] REQ-MOD-002 模块修改 + - [ ] REQ-MOD-003 模块删除 + - [ ] REQ-MOD-004 模块查询 + +- module_usr 用户管理 + - 依赖: — + - 路径: backend/module/usr/, frontend/pages/usr/ + - MR: — + - 功能: + - [ ] REQ-USR-001 用户新增 + - [ ] REQ-USR-002 用户修改 + - [ ] REQ-USR-003 用户查询 + - [ ] REQ-USR-004 用户登录 diff --git a/docs/09-项目目录结构.md b/docs/09-项目目录结构.md new file mode 100644 index 0000000..2f72287 --- /dev/null +++ b/docs/09-项目目录结构.md @@ -0,0 +1,121 @@ +# 09-项目目录结构 + +## 一、仓库顶层 + +``` +. +├── CLAUDE.md # Claude Code 主指令 +├── README.md # 项目说明(人工补充) +├── .env.local # 本地凭据(不入 git) +├── .gitignore +├── .githooks/ # 项目级 git hooks +│ └── pre-push # push 前触发本地全量测试闸门 +├── scripts/ # 工具脚本 +│ ├── test.sh # 全量测试入口 +│ └── setup-test-db.sh # DROP+CREATE 测试库 +├── sql/ +│ └── migrations/ # Flyway 顺序迁移文件 +│ └── V1__initial_schema.sql +├── docs/ # 见 § 四 +├── backend/ # 后端工程(Spring Boot + Maven) +└── frontend/ # 前端工程(React + Vite) +``` + +## 二、后端目录 + +根包名:`com.xly.erp` + +``` +backend/ +├── pom.xml +└── src/ + ├── main/ + │ ├── java/<根包路径>/ + │ │ ├── ErpApplication.java # Spring Boot 启动类 + │ │ ├── common/ # 通用组件 + │ │ │ ├── response/ # 统一响应封装 + │ │ │ ├── exception/ # 全局异常处理 + │ │ │ ├── security/ # JWT / Security 配置 + │ │ │ └── util/ + │ │ └── module/ # 业务模块(按 docs/01 模块代码分目录) + │ │ ├── usr/ # USR 用户管理 + │ │ │ ├── controller/ + │ │ │ ├── service/ + │ │ │ ├── mapper/ + │ │ │ ├── entity/ + │ │ │ ├── dto/ + │ │ │ └── vo/ + │ │ └── mod/ # MOD 模块管理 + │ │ ├── controller/ + │ │ ├── service/ + │ │ ├── mapper/ + │ │ ├── entity/ + │ │ ├── dto/ + │ │ └── vo/ + │ └── resources/ + │ ├── application.yml # 主配置 + │ ├── application-dev.yml # dev profile + │ ├── application-test.yml # test profile + │ └── mapper/ # MyBatis-Plus XML(按模块子目录) + └── test/ + └── java/<根包路径>/ + └── module/ # 与 main 同结构,测试代码 +``` + +## 三、前端目录 + +``` +frontend/ +├── package.json +├── vite.config.ts +├── index.html +└── src/ + ├── main.tsx # 应用入口 + ├── App.tsx # 根组件 + 全局 ConfigProvider + ├── api/ # 接口封装(按模块分文件,如 usr.ts / mod.ts) + ├── components/ # 通用组件 + ├── layouts/ # 布局组件(MainLayout 等) + ├── pages/ # 业务页面(按模块分目录) + │ ├── usr/ # USR 用户管理 + │ │ ├── UserList.tsx + │ │ ├── UserForm.tsx + │ │ └── UserDetail.tsx + │ └── mod/ # MOD 模块管理 + │ └── ModuleTree.tsx + ├── store/ # Redux Toolkit slices + ├── hooks/ # 自定义 hooks + ├── router/ # 路由配置 + ├── utils/ # 工具函数(日期、金额、权限判断等) + └── styles/ # 全局样式 / 主题 token +``` + +## 四、docs/ 结构 + +``` +docs/ +├── 01-需求清单/ # 每模块一子目录(_module.md 模块头 + REQ-*.md 卡片) +├── 02-开发计划.md +├── 03-数据库设计文档.md +├── 04-技术规范.md +├── 05-API接口契约.md +├── 06-UI交互规范.md +├── 07-环境配置.md +├── 08-模块任务管理.md +├── 09-项目目录结构.md +├── 10-验收检查清单.md +└── superpowers/ # CC 运行时产物 +``` + +## 五、命名与放置约定 + +- **根包**:`com.xly.erp`,所有 Java 类必须在此包或其子包下 +- **前端命名空间**:以 `src/` 为根,按模块代码(小写)建子目录 +- **Controller**:放 `module//controller/`,类名 `Controller`,提供 RESTful 接口 +- **Service**:接口 `Service` + 实现 `ServiceImpl`,放 `module//service/[impl/]` +- **Mapper**:接口放 `module//mapper/`,XML 放 `resources/mapper//` +- **DTO**:入参对象,放 `module//dto/`,命名 `DTO`(如 `CreateUserDTO`) +- **VO**:响应对象,放 `module//vo/`,命名 `VO` 或 `VO`(如 `UserListVO`) +- **Entity**:与数据库表 1:1 映射,放 `module//entity/` +- **前端组件**:通用组件放 `src/components/`,业务专用组件放 `src/pages//components/` +- **前端页面**:每个 REQ 一个页面文件,放 `src/pages//`,PascalCase 命名 +- **前端路由**:集中在 `src/router/`,按模块分文件后聚合 diff --git a/docs/10-验收检查清单.md b/docs/10-验收检查清单.md new file mode 100644 index 0000000..3a9c860 --- /dev/null +++ b/docs/10-验收检查清单.md @@ -0,0 +1,16 @@ +# 10-验收检查清单 + +通用验收项(全项目适用): + +- [ ] `scripts/test.sh` 本地全绿 +- [ ] 所有 schema 改动都有对应 `sql/migrations/V_n__.sql` +- [ ] 所有新接口在 `docs/05` 中有契约定义 +- [ ] 所有新功能代码注释含 REQ-XXX-NNN +- [ ] 统一响应格式 `{code, message, data, timestamp}` +- [ ] 异常走全局处理器,不暴露堆栈到前端 +- [ ] 前端不存敏感信息到 localStorage + +> 本文档仅维护项目级验收 SOP。粒度更细的验收信息分散在: +> - **每 REQ 的业务验收点**:`docs/01-需求清单//.md § 验收` +> - **每模块的实测验收(数据 / UI / 自动化用例位置)**:由 B 阶段 `module-report` 在该模块完成时填入模块完成报告 +> - **REQ 开发进度(feature-review approve 状态)**:`docs/08 § 二` diff --git a/scripts/setup-test-db.sh b/scripts/setup-test-db.sh new file mode 100755 index 0000000..41a3970 --- /dev/null +++ b/scripts/setup-test-db.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# scripts/setup-test-db.sh — 数据库重置脚本:drop + create 空库。 +# schema apply 由 Flyway 在 Spring Boot 启动时自动处理(见 docs/04 技术栈 + sql/migrations/V*.sql)。 +# seed 数据由测试框架负责(Spring @Sql / Flyway R__seed.sql / data.sql)。 +# +# 使用场景: +# - scripts/test.sh 开头:清空库,让 Spring 启动时 Flyway 从 V1 开始重放所有 migration +# - scripts/test.sh 结尾:清空库,避免测试遗留污染下次运行 +# - 手动调试时:reset 到零状态 +# +# 防护:本脚本只允许在本地 host + 测试库名上执行;非预期目标会被拒绝, +# 避免 .env.local 误指向 staging/prod 时触发不可逆 DROP。 + +set -euo pipefail + +ENV_FILE="$(dirname "$0")/../.env.local" +[ -f "$ENV_FILE" ] || { echo "[setup-test-db] ⚠️ .env.local 不存在($ENV_FILE)" >&2; exit 1; } + +# 用 set -a 加载,让 KEY=VALUE 导出为环境变量;密码中含特殊字符时 .env.local 请用单引号包裹 +set -a; . "$ENV_FILE"; set +a + +# 防护 1:默认只允许本地 host(localhost / 127.0.0.1 / ::1)。 +# 若要为本项目额外允许某些远程 host(如公司测试 MySQL),在 .env.local 里设: +# TEST_DB_ALLOWED_HOSTS="118.178.19.35 test-mysql.internal" # 空格或逗号分隔 +# 被列入者可直接 DROP CREATE,不再需要 TEST_DB_ALLOW_REMOTE=1。 +ALLOWED_HOSTS="localhost 127.0.0.1 ::1 ${TEST_DB_ALLOWED_HOSTS//,/ }" +host_allowed=0 +for h in $ALLOWED_HOSTS; do + [ "${DB_HOST:-}" = "$h" ] && { host_allowed=1; break; } +done +if [ "$host_allowed" -ne 1 ]; then + echo "[setup-test-db] ⚠️ 拒绝在非白名单 host (${DB_HOST}) 上执行 DROP DATABASE" >&2 + echo " 当前白名单:${ALLOWED_HOSTS}" >&2 + echo " 加入 host:在 .env.local 追加 TEST_DB_ALLOWED_HOSTS=\" \"" >&2 + echo " 一次性绕过:TEST_DB_ALLOW_REMOTE=1 $0" >&2 + [ "${TEST_DB_ALLOW_REMOTE:-0}" = "1" ] || exit 1 +fi + +# 防护 2:schema 名需像测试/开发库(含 test / _dev / _local),否则要求显式确认 +case "${DB_SCHEMA:-}" in + *test*|*_dev|*_local|*_ci) + ;; + *) + echo "[setup-test-db] ⚠️ schema '${DB_SCHEMA}' 不像测试库(期望命名含 test / _dev / _local / _ci)" >&2 + echo " 如确为期望行为,请显式声明:TEST_DB_ALLOW_PROD_NAME=1 $0" >&2 + [ "${TEST_DB_ALLOW_PROD_NAME:-0}" = "1" ] || exit 1 + ;; +esac + +# 防护 3:显式 banner,让人看见自己在 drop 什么;远程 host 额外提示白名单内容 +echo "[setup-test-db] 即将 DROP + CREATE \`${DB_SCHEMA}\` on ${DB_HOST}:${DB_PORT}" +case "${DB_HOST:-}" in + localhost|127.0.0.1|::1) ;; + *) + echo "[setup-test-db] ⚠️ 目标是 **远程** host(已在 TEST_DB_ALLOWED_HOSTS 白名单中,每次 test.sh 都会 DROP)" + echo "[setup-test-db] 当前白名单: ${ALLOWED_HOSTS}" + echo "[setup-test-db] 若不希望每次自动 DROP,从 .env.local 的 TEST_DB_ALLOWED_HOSTS 删掉此 host" + ;; +esac + +MYSQL_CMD="mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWORD}" + +$MYSQL_CMD -e "DROP DATABASE IF EXISTS \`${DB_SCHEMA}\`; CREATE DATABASE \`${DB_SCHEMA}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + +echo "[setup-test-db] done — schema will be applied by Flyway when Spring Boot starts" diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..2fdb4be --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# scripts/test.sh —— 合并到默认分支(main / master)前的测试闸门。 +# 顺序:setup-db → build → lint → unit+integration → e2e → reset-db +# 由 .githooks/pre-push 和 test-gate skill(通过子会话)调用。 + +set -euo pipefail + +PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$PROJECT_ROOT" + +echo "[test.sh] 1/6 setup test db" +./scripts/setup-test-db.sh + +echo "[test.sh] 2/6 build" +(cd backend && mvn -B -DskipTests clean package) && (cd frontend && npm ci && npm run build) + +echo "[test.sh] 3/6 lint" +(cd frontend && npm run lint) + +echo "[test.sh] 4/6 unit + integration" +(cd backend && mvn -B test) && (cd frontend && npm test -- --run) + +echo "[test.sh] 5/6 E2E" +echo "[test.sh] e2e 略" + +echo "[test.sh] 6/6 reset test db" +./scripts/setup-test-db.sh + +echo "[test.sh] GREEN" diff --git a/sql/migrations/.gitkeep b/sql/migrations/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/sql/migrations/.gitkeep diff --git a/sql/migrations/V1__initial_schema.sql b/sql/migrations/V1__initial_schema.sql new file mode 100644 index 0000000..dfa9192 --- /dev/null +++ b/sql/migrations/V1__initial_schema.sql @@ -0,0 +1,172 @@ +-- Flyway migration V1 — initial schema for 小羚羊 +-- Generated: 2026-04-29T01:46:21Z +-- Source: 由 A4 db-init 从 docs/03-数据库设计文档.md 翻译生成(schema SSoT 是 docs/03) +-- This is the FIRST migration; subsequent schema changes must be written as new files sql/migrations/V2__.sql, V3__... etc. +-- Apply: Flyway runs this automatically at Spring Boot startup. +-- Do not hand-edit this file after it is committed; write a new migration instead. + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ───────────────────────────────────────────────────────────── +-- tUser — 系统用户账户与登录凭据 +-- ───────────────────────────────────────────────────────────── +CREATE TABLE `tUser` ( + `iIncrement` INT NOT NULL AUTO_INCREMENT COMMENT '整数主键 ID(标准列)', + `sId` VARCHAR(100) NULL DEFAULT NULL COMMENT '业务 ID(标准列)', + `sBrandsId` VARCHAR(100) NULL DEFAULT NULL COMMENT '品牌 ID(多租户隔离,标准列)', + `sSubsidiaryId` VARCHAR(100) NULL DEFAULT NULL COMMENT '子公司 ID(组织层级隔离,标准列)', + `tCreateDate` DATETIME NOT NULL COMMENT '创建时间(标准列)', + `sUserNo` VARCHAR(50) NOT NULL COMMENT '用户号;系统内唯一', + `sUserName` VARCHAR(50) NOT NULL COMMENT '用户名(登录账号);系统内唯一', + `iStaffId` INT NULL DEFAULT NULL COMMENT '关联职员 ID(可选,外键 → tStaff.iIncrement)', + `sUserType` VARCHAR(20) NOT NULL DEFAULT '普通用户' COMMENT '用户类型;枚举:普通用户 / 超级管理员', + `sLanguage` VARCHAR(10) NOT NULL DEFAULT 'zh' COMMENT '语言偏好;枚举:zh / en / zh-TW', + `bCanModifyDocs` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '单据修改权限;0 否 / 1 是', + `sPasswordHash` VARCHAR(255) NOT NULL COMMENT '密码哈希值(BCrypt 等强哈希),新增默认初始密码 666666 的哈希', + `tLastLoginDate` DATETIME NULL DEFAULT NULL COMMENT '最后登录时间', + `sCreatedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '制单人(创建用户的操作员用户号)', + `bDeleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '软删除标记;0 有效 / 1 已作废', + `tDeletedDate` DATETIME NULL DEFAULT NULL COMMENT '软删除时间', + `sDeletedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '软删除操作人', + PRIMARY KEY (`iIncrement`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统用户账户与登录凭据'; + +-- ───────────────────────────────────────────────────────────── +-- tStaff — 职员维度(员工名 / 部门 / 编号) +-- ───────────────────────────────────────────────────────────── +CREATE TABLE `tStaff` ( + `iIncrement` INT NOT NULL AUTO_INCREMENT COMMENT '整数主键 ID(标准列)', + `sId` VARCHAR(100) NULL DEFAULT NULL COMMENT '业务 ID(标准列)', + `sBrandsId` VARCHAR(100) NULL DEFAULT NULL COMMENT '品牌 ID(多租户隔离,标准列)', + `sSubsidiaryId` VARCHAR(100) NULL DEFAULT NULL COMMENT '子公司 ID(组织层级隔离,标准列)', + `tCreateDate` DATETIME NOT NULL COMMENT '创建时间(标准列)', + `sStaffNo` VARCHAR(50) NULL DEFAULT NULL COMMENT '职员编号;系统内唯一', + `sStaffName` VARCHAR(50) NOT NULL COMMENT '职员姓名', + `sDepartment` VARCHAR(100) NULL DEFAULT NULL COMMENT '所属部门(本期暂用字符串,未来可独立 tDepartment 字典表)', + `sCreatedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '制单人', + `bDeleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '软删除标记', + `tDeletedDate` DATETIME NULL DEFAULT NULL COMMENT '软删除时间', + `sDeletedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '软删除操作人', + PRIMARY KEY (`iIncrement`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='职员维度(员工名 / 部门 / 编号)'; + +-- ───────────────────────────────────────────────────────────── +-- tPermissionCategory — 权限分类树 +-- ───────────────────────────────────────────────────────────── +CREATE TABLE `tPermissionCategory` ( + `iIncrement` INT NOT NULL AUTO_INCREMENT COMMENT '整数主键 ID(标准列)', + `sId` VARCHAR(100) NULL DEFAULT NULL COMMENT '业务 ID(标准列)', + `sBrandsId` VARCHAR(100) NULL DEFAULT NULL COMMENT '品牌 ID(多租户隔离,标准列)', + `sSubsidiaryId` VARCHAR(100) NULL DEFAULT NULL COMMENT '子公司 ID(组织层级隔离,标准列)', + `tCreateDate` DATETIME NOT NULL COMMENT '创建时间(标准列)', + `sCategoryCode` VARCHAR(50) NOT NULL COMMENT '权限分类编码;系统内唯一', + `sCategoryName` VARCHAR(100) NOT NULL COMMENT '权限分类名称(界面展示)', + `iParentId` INT NULL DEFAULT NULL COMMENT '父分类 ID(自引用,根节点为 NULL)', + `iSortOrder` INT NOT NULL DEFAULT 0 COMMENT '同级排序号', + `sCreatedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '制单人', + `bDeleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '软删除标记', + `tDeletedDate` DATETIME NULL DEFAULT NULL COMMENT '软删除时间', + `sDeletedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '软删除操作人', + PRIMARY KEY (`iIncrement`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='权限分类树'; + +-- ───────────────────────────────────────────────────────────── +-- tUserPermission — 用户与权限分类关联 +-- ───────────────────────────────────────────────────────────── +CREATE TABLE `tUserPermission` ( + `iIncrement` INT NOT NULL AUTO_INCREMENT COMMENT '整数主键 ID(标准列)', + `sId` VARCHAR(100) NULL DEFAULT NULL COMMENT '业务 ID(标准列)', + `sBrandsId` VARCHAR(100) NULL DEFAULT NULL COMMENT '品牌 ID(多租户隔离,标准列)', + `sSubsidiaryId` VARCHAR(100) NULL DEFAULT NULL COMMENT '子公司 ID(组织层级隔离,标准列)', + `tCreateDate` DATETIME NOT NULL COMMENT '创建时间(标准列)', + `iUserId` INT NOT NULL COMMENT '关联用户 ID(外键 → tUser.iIncrement)', + `iCategoryId` INT NOT NULL COMMENT '关联权限分类 ID(外键 → tPermissionCategory.iIncrement)', + `sCreatedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '授权操作人', + PRIMARY KEY (`iIncrement`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户与权限分类关联'; + +-- ───────────────────────────────────────────────────────────── +-- tModule — ERP 业务模块元数据树 +-- ───────────────────────────────────────────────────────────── +CREATE TABLE `tModule` ( + `iIncrement` INT NOT NULL AUTO_INCREMENT COMMENT '整数主键 ID(标准列)', + `sId` VARCHAR(100) NULL DEFAULT NULL COMMENT '业务 ID(标准列)', + `sBrandsId` VARCHAR(100) NULL DEFAULT NULL COMMENT '品牌 ID(多租户隔离,标准列)', + `sSubsidiaryId` VARCHAR(100) NULL DEFAULT NULL COMMENT '子公司 ID(组织层级隔离,标准列)', + `tCreateDate` DATETIME NOT NULL COMMENT '创建时间(标准列)', + `sDisplayType` VARCHAR(20) NOT NULL DEFAULT '手机端' COMMENT '显示类型;枚举:手机端 / 前端业务 / 系统配置 / 接口', + `sProcedureName` VARCHAR(100) NOT NULL COMMENT '存储过程(审核)名称;系统内唯一', + `sModuleType` VARCHAR(50) NOT NULL COMMENT '模块类型(本期自由文本,未来如收敛到枚举再加约束)', + `sManageDeptEn` VARCHAR(50) NOT NULL COMMENT '管理部门英文标识', + `bShowPermission` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '权限是否显示;0 否 / 1 是', + `sModuleNameZh` VARCHAR(100) NOT NULL COMMENT '界面名称(中文,模糊查询用)', + `iParentId` INT NULL DEFAULT NULL COMMENT '父模块 ID(自引用,根节点为 NULL)', + `iSortOrder` INT NOT NULL DEFAULT 0 COMMENT '同级排序号', + `sCreatedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '制单人', + `bDeleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '软删除标记', + `tDeletedDate` DATETIME NULL DEFAULT NULL COMMENT '软删除时间', + `sDeletedBy` VARCHAR(50) NULL DEFAULT NULL COMMENT '软删除操作人', + PRIMARY KEY (`iIncrement`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 业务模块元数据树'; + +-- ───────────────────────────────────────────────────────────── +-- 索引 +-- ───────────────────────────────────────────────────────────── + +-- tUser +CREATE UNIQUE INDEX `uk_user_no` ON `tUser` (`sUserNo`); +CREATE UNIQUE INDEX `uk_user_name` ON `tUser` (`sUserName`); +CREATE INDEX `idx_staff_id` ON `tUser` (`iStaffId`); +CREATE INDEX `idx_brand_subsidiary` ON `tUser` (`sBrandsId`, `sSubsidiaryId`); +CREATE INDEX `idx_deleted_login` ON `tUser` (`bDeleted`, `tLastLoginDate`); + +-- tStaff +CREATE UNIQUE INDEX `uk_staff_no` ON `tStaff` (`sStaffNo`); +CREATE INDEX `idx_staff_name` ON `tStaff` (`sStaffName`); +CREATE INDEX `idx_department` ON `tStaff` (`sDepartment`); + +-- tPermissionCategory +CREATE UNIQUE INDEX `uk_category_code` ON `tPermissionCategory` (`sCategoryCode`); +CREATE INDEX `idx_parent` ON `tPermissionCategory` (`iParentId`); + +-- tUserPermission +CREATE UNIQUE INDEX `uk_user_category` ON `tUserPermission` (`iUserId`, `iCategoryId`); +CREATE INDEX `idx_category` ON `tUserPermission` (`iCategoryId`); + +-- tModule +CREATE UNIQUE INDEX `uk_procedure_name` ON `tModule` (`sProcedureName`); +CREATE INDEX `idx_module_name_zh` ON `tModule` (`sModuleNameZh`); +CREATE INDEX `idx_parent_module` ON `tModule` (`iParentId`); +CREATE INDEX `idx_display_type` ON `tModule` (`sDisplayType`); + +-- ───────────────────────────────────────────────────────────── +-- 外键 +-- ───────────────────────────────────────────────────────────── + +ALTER TABLE `tUser` + ADD CONSTRAINT `fk_user_staff` + FOREIGN KEY (`iStaffId`) REFERENCES `tStaff` (`iIncrement`) + ON DELETE SET NULL ON UPDATE CASCADE; + +ALTER TABLE `tPermissionCategory` + ADD CONSTRAINT `fk_category_parent` + FOREIGN KEY (`iParentId`) REFERENCES `tPermissionCategory` (`iIncrement`) + ON DELETE RESTRICT ON UPDATE CASCADE; + +ALTER TABLE `tUserPermission` + ADD CONSTRAINT `fk_up_user` + FOREIGN KEY (`iUserId`) REFERENCES `tUser` (`iIncrement`) + ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE `tUserPermission` + ADD CONSTRAINT `fk_up_category` + FOREIGN KEY (`iCategoryId`) REFERENCES `tPermissionCategory` (`iIncrement`) + ON DELETE RESTRICT ON UPDATE CASCADE; + +ALTER TABLE `tModule` + ADD CONSTRAINT `fk_module_parent` + FOREIGN KEY (`iParentId`) REFERENCES `tModule` (`iIncrement`) + ON DELETE RESTRICT ON UPDATE CASCADE; + +SET FOREIGN_KEY_CHECKS = 1; -- libgit2 0.22.2