From 5b33c5f8d51a655b10f3cf087c23934eb7e0e264 Mon Sep 17 00:00:00 2001 From: Guilian Celin--Davanture Date: Wed, 10 Apr 2024 17:55:57 +0200 Subject: [PATCH] Much commit. switch to typescript, actual analysis, etc. --- bun.lockb | Bin 25144 -> 34747 bytes index.js | 73 ---- index.ts | 552 +++++++++++++++++++++++++++++++ package.json | 28 +- pep440version.ts | 416 +++++++++++++++++++++++ static/bars.svg | 52 +++ static/lib/graphology.umd.min.js | 2 + static/{ => lib}/htmx.min.js | 0 static/lib/sigma.min.js | 1 + static/styles.css | 228 +++++++------ tailwind.config.js | 4 +- views/dependency.liquid | 33 +- views/fullgraph.liquid | 49 +++ views/graph.liquid | 52 +++ views/index.liquid | 80 +++-- views/layout.liquid | 4 +- 16 files changed, 1352 insertions(+), 222 deletions(-) mode change 100644 => 100755 bun.lockb delete mode 100644 index.js create mode 100644 index.ts create mode 100644 pep440version.ts create mode 100644 static/bars.svg create mode 100644 static/lib/graphology.umd.min.js rename static/{ => lib}/htmx.min.js (100%) create mode 100644 static/lib/sigma.min.js create mode 100644 views/fullgraph.liquid create mode 100644 views/graph.liquid diff --git a/bun.lockb b/bun.lockb old mode 100644 new mode 100755 index 11643c17b2ace3e87894f4c01609a414be8e3a86..93cc8866c97e61d192f1e9aa115e02599b01c370 GIT binary patch delta 11664 zcmdT~30xD`)}KTY5_S+31F~<5Y(YV^MsPz3AgF)>Y6C<-*#inz4Qk!0xNz%+Z56eO zTh%JorCRN)TC1&E*W!xW#iedft#;Axeh3HHBOe|~e%0oy$@{!!v88_8Bx6<%7hYG$)zv1tzZdt_GwrgD5qo15yU zFCA=Po*xUe`9;~4SzLZzNqJuO2%U|Hf>pqGujubAU3!G8_j4%88HqI_OTj)`t9i=TS({Wr7DyU;-xh}J)lH)2R9A`!HisDkO zPREVXl%kg7j!O*+$|{Ssfq6P^mN^umT|r)fHZVJrn*^R5)0Jt;%5_@ZKD4(1za5nH z>9mE}q-Pm;DOKpDbFaHvWEs^?vtSM)UyC>++e6B_i+uGT7}*jyN+sUfplll`DPIeU zUsbL~S2Vg1a#RwZ1xn7Ofl?Hgp_1q#BfV_Pam~S}B6Jkpqu?nBIYq_1lRZ$6$m**W z!T}oP8N`qj95K?jP!HWz1=_OQqHG;k2%f^63QB`3FD%Y0)^c1Jc$%K9qN0&`;Qfqp zM^JJ=4oZ%eYDNcUA^}dpD%sPtAU%3aOJ$js2LCIjg+`{y%F-5N-cm8i)X*C;q5w~A zTNxZ3YNP`|$-oIva!laSoG$^xt_+^KwrF0`l2+N5tWG7JvWYBoXrb z8S~)MD7Wv@T&>IdJiK~VQ8^+!lT`v!atath`W5TT;%G3!~pSJroTk+QB@5gMF zjNcOV;rw-G>F@99SYy52YK(tK{FC$zrW33$kp!B+3d~li0_N^bL*F`?m1`Cy)UF~cd0`r z+<)U{&X?01Zg?&~w6Jo?h_CbJ2B%f~Hgt`Y7rnOsdQ$C9fyb4=mxWI5or977LRn)h zdmIh*KDeZ)R6Did+aXMRF;?4fbHGL*c2wJ(%{2>PNA2X)sJM%ZI8wysn6+ni5}ExCV-r&52gsn%k0g>%v{SJm@-Ffsob{oOtVteW{}H&p z;HU?Zl`|K5SaZ#g@pN4RCHOgBc{ zG9DG}`EF~hSgoZ>ei;=icqw6Z<`H6dYo@SLi3eM=G?4w)tQN%5hBaEL5G zXAvP;2Ch461Bb5KkVT0n)}qdAh(#B92Axs(DAwZnwk*v?C4OMbYHd`KBCINd*t=+T z0B8IhuqIiAq&Zfh5Pp0;>{+d?O3qO6njv~N5#lC$rm$1Vow3-FW)6uPAx?H+wRS4W zB2x#XXx#F_I3uq`yqRineb^AIF7lJcdXCk}BE)h>mgb-m_jP2o zAPXE>qk~F*35%Lx0+G&Qrxq-&xk_Gu6^?R4%seC!^7Y`9;F=L9xd;w1!JK%sWND5n zv8E-fbquG}mA{LHkH&+RvIzTcz=e}nNI)u9LZaF`VZozIQIL2)ljJ}`BSBhmNKno~ zkXSETAuhpB~xP*qSQYH_W6=xAgFlG)5z(M36=i~B|{m! zmX}bnPYs3u#w+UEnbMwSB9PiLfMMp_O^Q&Is?B=uu(pz>EJ z{xoqD_||_;$?!yg@@W=81FHe3o&i*hR4<(HlsuZpi(jPFaXvuug#hu3jI(a)Hx|?o zxh=VVa#Hu>vCBC&t92`V(jk^~Gj`Hb@uKn5t}cIlO8n@RL(bh*)GhwDCT-2R(>oHo zeSPKqN!L1U{KEP8Oi9x}BsTXCwSDSz{llEQ7Jf4ye*t$z+!Na;m|j{&gkpARl6&LH zn^P9`Eb!QTVC%}mzgqZTnzG}~x!vw8w?7xcq7xL!&TCi4Dt64AqzxNflOI#IIPd#u zL&nWM*#9H-kE74;;FwC$O5b+NZ}LdnC$}DctdSq_9(i_VFUy_lypFX$x7k;AcmH1N z*n}@y&vxM+4zSqwpu^^X<47|J+3Gdf3pkDReUn+jB3TD)y^j(zB#_3WR1S- zuD~kaojne8<=8E_H(zvTe@61DW$q_>ufDlWHl`}YeQ##|4`<`#^hMOTjrQJ;--8= z%H00zudF*%{n?IR>*`1PO&?ow@3qLHJ@7|xPcHZdYSwH^>b4cZqgKrCyyzG0K>wz| zpSq|&9eXDy$?um|q7H|T)_%CIb#m{CiXm5SrOk?w&f9q7)9Jcqi?c(owM>}mKYpf$ zV+k(Ey%~GfKKQiR$GKAn-5M0$er@@d^!7I9*L8P4Z}Coi`jz>^%07?&xcJ7z?8(j* zrz_uH+jzYB>zk%J>Z%`KlOC@bT4>@P{eKaP*)prW6+?RM%D+<6Ho!e2bV^F<$6a@S zni6?At?t8y)$0%RoAp-QnI$obrH5VnXS(lQaXV|u3C*CD?+4h7x^w$fvtund_5|)N zJ~eaKM`hc>E{=_=niDi)$A+-t~1v%QMtZ|ze~k2$?u=6iE*OykG$!^;BB#-1BF zH@{8s%Wo_zcr$3AG&N`JAU zL+4>Rb8~uJzgB$XtJ~9qoqV{G`a<=fiJcv1t=ci9?b`a8jTd^hTRST*@$A9yZ+o`+ z>i+DVZO4at9ojzbrxmmw3+~~c`mr(Y@ZLH3GA9gLU{Dkl1xiQYiI5yO^mA=~Nqko*< zQ2*sG$$4g~?hh>ziu+gB-dnll+}<4iBzdH2O>lB3X`Kv|Un8qLD z1Gf)cG_!A;D(cSiaO}bM;@Fe5ZkH-|FTE1cPPCxVY{$pi+ce6F=E4QxyeC6;_qHc|$t^xNujoqEDy87DQ-5*Wd zKkEF0Unck}OtN91sowgBk6RpGTKIO&iKBa~^XJHOrs*GcU$EELAtuRh=f{hGZq}+Q zL#k|D+WAq7r<;1OKf7nvzy*U_c6N_gz3i*2ck}l&m?)-a6rq?+Smu1PeVuvt!DA=5 z-_~F4Gib!Jl?j? z_Lrrxt?19Q5DDRLAt^W8o$ZixpmBapyJK!6Ze9JMG5O}TrfDlL7H=&*uY9UbsqvE8 zKH2^-X?bLFUF!QD(>5JQUn+B$G)3Qa_ZwzTmp0uu(VI#Njm7NT+O^FOrJ3*5Puw-9 z-+PkuReiIsdM>+jWZ1*_ksGIVy*X3}xrU#?S)<)EC^7t-s zUc#5&!MomEIJi~^k{x1b?s05*Gtt&J*tR;wd*_NN8=6Lr3hHOn zMepwDS)EFSle=qY!|C%QJ)O}55fwA0v1%^*e|XdjBcRdHttBfzFKC30#$Fej z>G_A;zuCy2*uZ1M-#EHIF>JJ}|IdZ`rOxPS-v4{y$79=nHT*imW9v&p^B;+f(f)re z3I+es@Z;rXFk5OSW4RLl%}YaE?O0;)XBOLx%lG}k>_Al4UdYBLPYs07eIkp^nalI*JXoBN;v4PYjqFJZOasiwH znyi*U3wpogh!dK@R)7;A7$HT}NiZH@A|nR`V(hE z=mbL@gF5h;iVUt2K2Y`fW!$B{;N1Xit8a#!aIyr*svjd zK!=37z?iV5L-@pQP#1|#!sZU)W4oabg-+PMA$(0Ii6IJma4F-WtKz@6>+!+epe_QP zguNibr+G+}K^=mSRF}~SmwlD+5ufi9MlR4LWI7RcB2`!T3?GCYCc+1QUK<6$q>tY4 z?cdlbEGXm^E-3#s7hbB3kG9cm{j&rzxPWAMxeIU&>k3vwEQ(daRs>^wAbEKdNZYF- zr{rkkjGlJR2s;^|E-Z*Q^or0S3NJT=#19en-3a?2pe-~goZJ?6;s`q}0*B@=(ODqbdc_gD!{^n41zDM-A^GQFi7K=iH=nB9>C}mc? zl;SWci|Q38#%7yYy`02xQdW=3R4F?Lk|kw!y`98`Qr51wQmmJ#!y_mxKByhI<#9RWtY(F11b9%+;%Aoig6O}lQQ>MB^wi?5FeMa`7uhDNx09@ zjARa8HDTj-vpbO;&pI^xmkSdn{RJlwc^!tl1v5lX$H)yAbCj-e%42 z#KMB1GTw&Gge=X5sX(%9*dVo1Y^Zb*_7FKOd1Fy^{XnHrBPR02&PK(TZJAA+lZ$bu zQPoM8J?92&`D}%8lHuXYda+q?ig01m(lVQc+smtWMi~uZ!e8xz!DzU!U+U(Du62$L z$^J%bSSeoJ)!+x~8Lto@v1hNxJBiQOvoZ0)9JvTvwhne{JiL3_;w@s)cqA#UK8B=W zjtLzoAz~AhV&vWUgyBMNopP+{=VY8irtCNIc|AMYPw8UV1I1N6w)Sjj5w-M=Sd`p? z|A$kBByml2(hGZ_N+lz|`yp!1Bg&$1GRz6PpoFbLbWOk|+@^*7Pr@c4c#DfAG&Cqo z*fAw+D}tmGE|<`dm-J}|8~jaL*j6R%Jwm6BLCSDs*sCRj4EIrPVIfOPjEepJ4deh+ zIo-V62uedCVKMl?- zFU%>`6z3M@7v)q2@^uI?IVB>8u5K+fE8&sAvCNr-v z*f2`gl;P?x1O#n`(?H`bm0D*N6%=R+v$dtHDaqOC8Hd)-&e5D5N%qp4xch=bX!|Nr zAb(pYJ5iNI1v%w;Wx3i?ttLM>SDRm~E!COy%PY*z%hHk10B1x1B|VMI(QdlRb7c*|YN>w7j$@UHqXG(_%^wnuGEJ%8}M4JUW_iY{Nhwm*>h~ z)Qb3Yq@ddycFIC%I0+16bJM&6{&?L`3&W;alZy$F=tv>+G2G|T#&Cjq+~mnyT^aJL zK&RD|X62H*Zl)DzZ_4sGe`lHiujfkuZ@Lf~5LG1^ z#K)&=q_CbQ3QZ)?&4BI*}N q3#}5vhPraPcJiK?_cY;2lPMd>FQ^?UQQcml6stEMN){cw@P7cW;_=A< delta 4393 zcmcgvZETa*6~6Zdlh}zvLI@ae8WJER4t8QEu@juUB!RS9%~}{?4(*0;5(6>h3kN9c zM%=0>`O#^R16s=vg|3qz8>NV{F)9#fWrC{e)&f&Ek*(EKmLe)OEtP0Bu|4PY`kgVrAq#bfYB;K>F8|`UHegKm7?1i*Kj-nsS zD~8O26FK0+kPgUn$f=O)dwO+ycYse5VjyuDO7We@fj2yX&5##R&jxfw`#1D-#KjTt zZ17=7c6>{BZ)a~*2-qaDz}tIzHgTW(b!^ zv~BOlvI-FZ*waXRd$hMdE`~8H8-{AV{BkTsNlAUpi)n3|RSLRc)6`5!u5``%9YjS# zUrFPW18PvxNV=vjOS%D(rO1_`Sszo$E`r9b0qah%Y79{NfHR72WN1pJkjt*A#uSP{ z#8YSl;slsgvy7);03A&Ws**_*%hW8ZCJ9kaUAEdu_|T{;J81nAzUoaYEK@A{h}59v zF?^vbdThg&kA0%?)POo-Ay<~B{%WBZ#Ei)_lBHQzOcugVpJfEq;AC=TYwGutDF*Qg znzJ=)9^%WMTIjevpq@@8*HlgINu?NsOrsHqN7LxWRLyz>nNg{`cswg$83k)3cY09e zTUnjuhY0o}>dFdQf6iY?v#kO3KANX#s@z5+(=^KnBG5`l(MutS%k*A-*#YYlVCBg% zSnwU`G?J@X-$P}suCZ@gKshtWHC?lQAIZYA!{v;C+Lb{g(>2Q#RQlN(s|_K4+?>eL z0#?t?Tle6Ltw+GK1D1{%bc^_u}M_mXVTK)>Fc{NVwNhnNck6O%!= z;^F23*8grYBv+vxf@Awoa)IOjZ8G4S%f0yjD;IFuC6j}bLC*!ME9|Aw;t<^~v{O|{ z2nWVzU&+1@Z!m)dEIHza4%d9X3C`M!|Mqds4lURr3Ut6=$5P!XnP zx1DxYgk%A|4|W@@sxl6gu7!Vo_*WZ}K{^jM1~$JgB5pH+6bq@e_T`wOQ5%j;tLVqx&cBW513vxE#1oD7KfP8?r zC%zv=fGDsYhyj}bJ`DUo4NwVSFMV3H;)8ehGGGo+2=JcAf95&>*9YAX-oTpy9KWIw zSOP2sc;kK&SPtNf7em~L(z=v=<$tBVB)k+n73;=TO25CcExbvwFYG7##y+yI6#)Cq zYvBXD0Iw7K%WB*J`^@Xd{^K&i_dmXr3S3_FtsCdXfPPr;it|Rq2aKtNC*nb-a*mnV z#s-+mIUpPuR?fL}3VjrD_<174A+hkCt2dASIj2cUug6!8k$P5Pg%hJo8m^75_~wX`<(?`J zThb=z;Kp29(w3*X1+}#;Q+OY}(dJNtg5GKKsbN8P+I-Ff#?;?^`E1~ywijPl(&s7n zaP}M#w5;8yP76x3`)0}2cYAXXJ7v5;TE5v z18ZmKFb3I~`8rm6*8dJa=v7n{U6C)W{~^V-UU3IZF-O=v@rFzczh-zxk}a zd93cxw3Dlfjft^G+ { - res.render('index'); -}) - - -function extractInfoFromPythonDepString(depstring) { - const info = { - name: "", - version_operator: "", - version: "", - } - - const parts = depstring.split(';'); - - const namever = parts[0]; - // https://stackoverflow.com/questions/24470567/what-are-the-requirements-for-naming-python-modules - const match = namever.match(/^(?[a-zA-Z_][a-zA-Z_0-9]*)(?.=)(?[0-9.])/); - if(match !== null && match.groups !== undefined) { - info.name = match.groups['name']; - info.operator = match.groups['operator']; - info.version = match.groups['version']; - } - - - - return info; -} - -app.post('/api/dependency', async (req, res) => { - const packagename = req.body.package; - console.log(packagename) - - const pypires = await fetch(`https://pypi.org/pypi/${packagename}/json`); - const json = await pypires.json(); - - const name = json.info.name; - const summary = json.info.summary; - - const deps = json.info.requires_dist.map( e => extractInfoFromPythonDepString(e) ); - - const versions = json.releases; - const latestVersionNumber = Object.entries(versions).sort( ([k1, v1], [k2, v2]) => k2 - v2 )[0]; - - const latestVersion = versions[latestVersionNumber]; - - const size = latestVersion.sort((a, b) => b.size - a.size )[0].size; - - res.render('dependency', { - name: name, - summary: summary, - weight: size, - dependencies: deps - }) -}); - -app.listen(8080) \ No newline at end of file diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..9ebcc38 --- /dev/null +++ b/index.ts @@ -0,0 +1,552 @@ +import path from 'node:path'; +import express from 'express'; +import {Liquid} from 'liquidjs'; +import {RateLimit} from 'async-sema'; +import fileUpload from 'express-fileupload'; + +import Graph from 'graphology'; +import forceAtlas2 from 'graphology-layout-forceatlas2'; +import circular from 'graphology-layout/circular'; +import {assignLayout} from 'graphology-layout/utils'; + +import {singleSource, singleSourceLength} from 'graphology-shortest-path/unweighted'; + +import Pep440Version, {Pep440VersionRule} from './pep440version.ts'; +import {version} from 'bun'; + +const liquidEngine = new Liquid({root: path.resolve(__dirname, 'views/'), jsTruthy: true}); + +const app = express(); + +app.use(express.json()); // To support JSON-encoded bodies +app.use(express.urlencoded()); // To support URL-encoded bodies +app.use(fileUpload({ + limits: { fileSize: 50 * 1024 * 1024 }, +})); + +app.engine('liquid', liquidEngine.express()); +app.set('views', [path.join(__dirname, 'views')]); +app.set('view engine', 'liquid'); + +app.use('/static', express.static('static')); + +app.get('/', (request, res) => { + res.render('index'); +}); + + +declare class RateLimit { + constructor(max: number); +} + +const rateLimit: any = new RateLimit(5); + + + +function extractInfoFromPythonDepString(depstring: string) { + const parts = depstring.split(';'); + + const namever = parts[0]; + + // https://stackoverflow.com/questions/24470567/what-are-the-requirements-for-naming-python-modules + const match = namever.match(/^(?[a-zA-Z_\-][\w\-]*)((?.=)(?.+))?/); + + + if (match !== null && match.groups !== undefined) { + let rule; + + if( match.groups.version ) { + const version = new Pep440Version(match.groups.version); + + rule = new Pep440VersionRule( + version, + match.groups.operator + ) + } + else { + rule = Pep440VersionRule.getRuleMatchingAnyVersion() + } + + return { + name: match.groups.name, + rule: rule + }; + } + else { + return undefined; + } +} + +async function getRawPackageInfo(packagename: string) { + await rateLimit(); + + const pypires = await fetch(`https://pypi.org/pypi/${packagename}/json`); + const json = await pypires.json(); + + return json; +} + + +interface PipReleaseFile { + size: number; + packagetype: string; + upload_time_iso_8601: string; + [key: string]: any; +} + + + + + +async function getFullPackageInfo(packagename: string, rule: Pep440VersionRule = Pep440VersionRule.getRuleMatchingAnyVersion(), fromGraph = new Graph()) { + const dependencyGraph = fromGraph; + + // Analyse the requested package + + const packageJson = await getRawPackageInfo(packagename); + + let longestDependencyChain = 0; + + //const dependenciesList = packageJson.info.requires_dist ?? []; + + const recurseDepsPackageInfo = async (packagename: string, rule: Pep440VersionRule = Pep440VersionRule.getRuleMatchingAnyVersion(), descPath: string = "") => { + console.log(`[Recurse] Going to scan package ${packagename}`); + + if( descPath == "" ) { + descPath = packagename; + } + else { + descPath += `/${packagename}` + } + + if( dependencyGraph.hasNode(packagename) ) { + // figure out if the current path taken to this package is shorter than the one in the graph + + // have to add the current package name manually as it isn't added yet + const paramPathParts: string[] = descPath.split('/'); + const graphPathParts: string[] = dependencyGraph.getNodeAttribute(packagename, 'path').split('/'); + + if( paramPathParts.length < graphPathParts.length ) { + // if so, change the graph path to the current one + dependencyGraph.setNodeAttribute(packagename, 'path', descPath) + console.log(`[Recurse] Found better way of getting to ${packagename}: ${descPath}`); + } + + const shortestDist = Math.min( paramPathParts.length, graphPathParts.length ); + if( longestDependencyChain < shortestDist ) { + longestDependencyChain = shortestDist; + } + + console.log(`[Recurse] Already scanned ${packagename} ; skipping.`); + return; + } + + console.log(`[Recurse] Scanning package ${packagename}`); + + const json = await getRawPackageInfo(packagename); + + // ================================================== + // 1. get biggest file of highest possible version + // TODO: don't choose biggest file, choose in a smart way (like asking the user's OS and arch) + + const releasesEntries = Object.entries(json.releases as {[key: string]: PipReleaseFile[]}); + + const releases: {[key: string]: PipReleaseFile[]} = {}; + + for( const [version, data] of releasesEntries ) { + try { + releases[new Pep440Version(version).releaseString()] = data; + } + catch { + console.log(`Failed to parse version: ${version}`); + } + } + + const versions = Object.keys(releases).map( v => { + console.log(`[Recurse] Parsing version ${v} for ${packagename}`); + return new Pep440Version(v); + }); + const highestVersions = rule.getSortedMatchingVersions(versions); + + if( highestVersions.length === 0 ) { + throw new Error("MERDE!"); + } + + + let highestVersion: undefined | Pep440Version = undefined; + + for( const version of highestVersions ) { + if( releases[version.releaseString()].length !== 0 ) { + highestVersion = version; + break; + } + } + + if( highestVersion === undefined ) { + throw new Error("MERDE!"); + } + + const highestRelease = releases[highestVersion.releaseString()]; + const biggestFile = highestRelease.sort( (a, b) => b.size - a.size )[0]; + + console.log(`[Recurse] ${packagename} has highest version ${highestVersion.releaseString()}`); + + // ================================================== + // 2. add to the graph + + const summary = json.summary; + + dependencyGraph.addNode(packagename, { + label: packagename, + size: 10, + + summary: summary, + version: highestVersion.releaseString(), + weight: biggestFile.size, + path: descPath + }); + + + + ///////////////// + + const dependenciesList = packageJson.info.requires_dist ?? []; + + console.log(`[Recurse] ${packagename} has deps:\n - ${dependenciesList.join('\n - ')}`); + + for( const depString of dependenciesList ) { + console.log(`[Recurse] ${packagename} depends on: ${depString}`); + + const info = extractInfoFromPythonDepString(depString); + + if( info === undefined ) continue; + + await recurseDepsPackageInfo(info.name, info.rule, descPath); + + if( dependencyGraph.hasEdge(packagename, info.name) === false ) { + dependencyGraph.addEdge(packagename, info.name); + } + } + } + + await recurseDepsPackageInfo(packagename, rule); + + console.log(`Longest dependency chain is ${longestDependencyChain}`); + + + + //const paths = singleSource(dependencyGraph, packagename) + + + + const depthColors = [ + "#D14D41", + "#DA702C", + "#D0A215", + "#879A39", + "#3AA99F", + "#4385BE", + "#8B7EC8", + "#CE5D97", + ] + + const lengthmap = singleSourceLength(dependencyGraph, packagename); + const longestPathLength = Math.max(...Object.values(lengthmap)) + + for( const [node, dist] of Object.entries(lengthmap) ) { + dependencyGraph.setNodeAttribute(node, 'color', depthColors[dist + 1] ) + dependencyGraph.setNodeAttribute(node, 'actual_depth', dist ) + } + + + dependencyGraph.forEachEdge((edge, attrs, source, target, sourceAttrs, targetAttrs) => { + const sourceDepth = sourceAttrs.actual_depth; //.path.split('/').length - 1; + const targetDepth = targetAttrs.actual_depth; //.path.split('/').length - 1; + + if( sourceDepth >= targetDepth ) { + dependencyGraph.setEdgeAttribute( edge, "color", "#B7B5AC") + dependencyGraph.setEdgeAttribute( edge, "size", 1) + + dependencyGraph.setEdgeAttribute( edge, "weight", 1) + } + else { + dependencyGraph.setEdgeAttribute( edge, "color", depthColors[ sourceDepth ]) + dependencyGraph.setEdgeAttribute( edge, "size", 3 + 3 * (longestPathLength - sourceDepth)) + + dependencyGraph.setEdgeAttribute( edge, "weight", 3 + 3 * (longestPathLength - sourceDepth)) + } + + dependencyGraph.setEdgeAttribute( edge, "type", "arrow"); + }); + + + + + + + + //circular.assign(dependencyGraph, {scale: 100}); + //forceAtlas2.assign(dependencyGraph, 100) + + + dependencyGraph.setNodeAttribute(packagename, 'size', 20) + //dependencyGraph.setNodeAttribute(packagename, 'x', 0) + //dependencyGraph.setNodeAttribute(packagename, 'y', 0) + + + + circular.assign(dependencyGraph, {scale: 100}); + + + + const positions = forceAtlas2(dependencyGraph, { + iterations: 50, + settings: { + edgeWeightInfluence: 1, + ...forceAtlas2.inferSettings(dependencyGraph), + } + }); + + assignLayout(dependencyGraph, positions); + + + return dependencyGraph; +} + +app.get('/graph/:packagename', (req, res) => { + const packagename = req.params.packagename; + + res.render('graph', { + packagename: packagename, + }) +}); + +app.get('/api/graph/:packagename', async (req, res) => { + const packagename = req.params.packagename; + + const depGraph = await getFullPackageInfo(packagename); + + const serializedDepGraph = depGraph.export(); + + let totalDownloadSize = 0; + + depGraph.forEachNode((node, attrs) => { + totalDownloadSize += attrs.weight; + }) + + const units = [ + 'b', + 'kb', + 'Mb', + 'Gb' + ] + + let currentUnit = 0; + while( totalDownloadSize > 1000 ) { + totalDownloadSize = totalDownloadSize / 1000; + currentUnit++; + } + + const unit = units[currentUnit]; + + res.json({ + weight: totalDownloadSize, + weightUnit: unit, + graph: serializedDepGraph + }); +}); + + +app.post('/api/upload-requirements', async (req, res) => { + // get the uploaded requirements.txt file, from the input with the name "file" + const files = req.files; + + if( files === undefined || files === null ) { + res.status(400); + res.send("No file uploaded"); + return; + } + + const file = files.requirementsFile; + + if( file === undefined || file === null ) { + res.status(400); + res.send("No file uploaded"); + return; + } + + if( Array.isArray(file) ) { + res.status(400); + res.send("Don't send multiple files."); + return; + } + + // convert to string + const content = '' + file.data; + const infos = content.replaceAll('\r\n', '\n').split('\n').map(extractInfoFromPythonDepString); + + let dependencyGraph = new Graph(); + for( const info of infos ) { + if( info === undefined ) { + console.log(`Got an undefined info !`) + continue; + } + + dependencyGraph = await getFullPackageInfo(info.name, info.rule, dependencyGraph); + } + + const serializedDepGraph = dependencyGraph.export(); + + + + + const getHumanWeight = (weight: number) => { + const units = [ + 'b', + 'kb', + 'Mb', + 'Gb' + ] + + let currentUnit = 0; + while( weight > 1000 ) { + weight = weight / 1000; + currentUnit++; + } + + return `${Math.round(weight)}${units[currentUnit]}` + } + + + + let nbNodes = 0; + let totalDownloadSize = 0; + + dependencyGraph.forEachNode((node, attrs) => { + nbNodes++; + totalDownloadSize += attrs.weight; + }) + + + let packageByWeight: {name: string, weight: number, humanWeight: string}[] = []; + + dependencyGraph.forEachNode((node, attrs) => { + packageByWeight.push({ + name: node, + weight: attrs.weight, + humanWeight: getHumanWeight(attrs.weight), + }) + }); + + packageByWeight = packageByWeight.sort( (a, b) => b.weight - a.weight); + + + + const humanDownloadSize = getHumanWeight(totalDownloadSize); + + + + + res.render('fullgraph', { + //packagename: packagename, + nb_deps: nbNodes, + totalWeight: { + raw: totalDownloadSize, + value: humanDownloadSize, + }, + graph: serializedDepGraph, + packageByWeight: packageByWeight + }); +}) + + + +/** + * Get info about a package + */ /* +async function getFullPackageInfo(packagename: string, versionRequirement={operator: "", version: ""}, seenBefore: Set = new Set([])) { + const packagejson = await getRawPackageInfo(packagename); + + const name = packagejson.info.name; + + const summary = packagejson.info.summary; + + const dependenciesList = packagejson.info.requires_dist ?? []; + + + const builtDepsList: Map + + + for( const depString of dependenciesList ) { + const dep = extractInfoFromPythonDepString(depString); + + if( seenBefore.has(dep.name) ) { + continue; + } + + const json = await getRawPackageInfo(dep.name, dep.version) + + + } + + +}*/ + + + + + + +/* +app.post('/api/dependency-tree', async (request, res) => { + const packagename = request.body.package; + console.log("Requested package: ", packagename); + + const json = await getRawPackageInfo(packagename); + + const name = json.info.name; + const summary = json.info.summary; + + let deps = json.info.requires_dist ? json.info.requires_dist.map(e => extractInfoFromPythonDepString(e)) : []; + // avoid duplicates (sometimes packages list themselves as a dependency to create "dependency groups" (?)) + deps = deps.filter( dep => dep.name !== packagename ); + + const versions = Object.entries(json.releases).filter( ([k, v]) => v.length > 0 ); + + // sort by size, preferring wheels + const versionsSorted = versions.map( ([versionNumber, filesArray]) => { + const wheels = filesArray.filter( file => file.packagetype === 'bdist_wheel' ); + + if( wheels.length > 0 ) { + // sort by size + const biggestWheel = wheels.sort( (a, b) => b.size - a.size )[0]; + + return [versionNumber, biggestWheel]; + } + else { + const biggestFile = filesArray.sort( (a, b) => b.size - a.size )[0]; + + return [versionNumber, biggestFile]; + } + }); + + + //const sorted = filesArray.sort( (a, b) => b.upload_time_iso8601 - a.upload_time_iso8601 ); + + const [latestVersionNumber, latestVersion] = versions[0]; + + const sortedFiles = latestVersion.sort((a, b) => b.size - a.size); + const size = sortedFiles[0].size; + + res.render('dependency', { + name, + summary, + weight: size, + dependencies: deps, + // DEBUG + has_parent: request.body.isfirst !== "true", + }); +});*/ + +app.listen(8080); + diff --git a/package.json b/package.json index f4dc3c0..853046a 100644 --- a/package.json +++ b/package.json @@ -1 +1,27 @@ -{"dependencies":{"express":"^4.19.2","liquidjs":"^10.10.2"},"name":"depyth","module":"index.js","type":"module","devDependencies":{"@types/bun":"latest"},"peerDependencies":{"typescript":"^5.0.0"}} \ No newline at end of file +{ + "name": "depyth", + "dependencies": { + "async-sema": "^3.1.1", + "express": "^4.19.2", + "express-fileupload": "^1.5.0", + "graphology": "^0.25.4", + "graphology-layout": "^0.6.1", + "graphology-layout-forceatlas2": "^0.10.1", + "graphology-shortest-path": "^2.1.0", + "liquidjs": "^10.10.2", + "melodyc": "^0.19.0" + }, + "scripts": { + "css:watch": "npx tailwindcss -i ./input.css -o ./static/styles.css --watch", + "css:watch:prod": "npx tailwindcss -i ./input.css -o ./static/styles.css --watch --minify" + }, + "module": "index.js", + "type": "module", + "devDependencies": { + "@types/bun": "latest", + "graphology-types": "^0.24.7" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/pep440version.ts b/pep440version.ts new file mode 100644 index 0000000..efeff18 --- /dev/null +++ b/pep440version.ts @@ -0,0 +1,416 @@ +import { compiler } from "melodyc"; + +/* +VERSION_PATTERN = r""" + v? + (?: + (?:(?P[0-9]+)!)? # epoch + (?P[0-9]+(?:\.[0-9]+)*) # release segment + (?P
                                          # pre-release
+            [-_\.]?
+            (?P(a|b|c|rc|alpha|beta|pre|preview))
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+        (?P                                         # post release
+            (?:-(?P[0-9]+))
+            |
+            (?:
+                [-_\.]?
+                (?Ppost|rev|r)
+                [-_\.]?
+                (?P[0-9]+)?
+            )
+        )?
+        (?P                                          # dev release
+            [-_\.]?
+            (?Pdev)
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+    )
+    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
+"""
+*/
+
+const VERSION_PATTERN = `
+	;
+
+	option of "v";
+
+	match {
+		option of match {
+			capture epoch {
+				some of ;
+			}
+			"!";
+		}
+
+		capture release {
+			some of ;
+			any of match {
+				".";
+				some of ;
+			}
+		}
+
+		option of capture pre {
+			option of either {
+				".";
+				"_";
+				"-";
+			}
+			capture pre_l {
+				either {
+					"a";
+					"b";
+					"c";
+					"rc";
+					"alpha";
+					"beta";
+					"pre";
+					"preview";
+				}
+			}
+			option of either {
+				".";
+				"_";
+				"-";
+			}
+			capture pre_n {
+				some of ;
+			}
+		}
+
+		option of capture post {
+			either {
+				match {
+					"-";
+					capture post_n {
+						some of ;
+					}
+				}
+
+				match {
+					option of either {
+						".";
+						"_";
+						"-";
+					}
+					capture post_l {
+						either {
+							"post";
+							"rev";
+							"r";
+						}
+					}
+					option of either {
+						".";
+						"_";
+						"-";
+					}
+					option of capture post_n {
+						some of ;
+					}
+				}
+			}
+		}
+
+		option of capture dev {
+			option of either {
+				".";
+				"_";
+				"-";
+			}
+			capture dev_l {
+				"dev";
+			}
+			option of either {
+				".";
+				"_";
+				"-";
+			}
+			option of capture dev_n {
+				some of ;
+			}
+		}
+
+		option of match {
+			"+";
+			capture local {
+				some of either {
+					a to z;
+					0 to 9;
+				}
+
+				any of match {
+					option of either {
+						".";
+						"_";
+						"-";
+					}
+					some of either {
+						a to z;
+						0 to 9;
+					}
+				}
+			}
+		}
+	}
+
+	// get rid of random bullshit at the end
+	capture random_bullshit {
+		any of ;
+	}
+
+	;
+`;
+
+/*
+ 
+	*/
+
+
+const output = compiler(VERSION_PATTERN);
+console.log(output);
+const VERSION_REGEX = new RegExp(output);
+
+
+export default class Pep440Version {
+	epoch?: number;
+	release: {
+		major: number;
+		minor: number;
+		patch: number;
+	};
+	preRelease?: {
+		name: string;
+		version?: number;
+	};
+	postRelease?: {
+		name?: string;
+		version?: number;
+	};
+	dev?: {
+		name: string;
+		version?: number;
+	};
+
+	random_bullshit_at_the_end?: string;
+
+
+
+	/**
+		*
+		* @param {string} versionString
+		*/
+	constructor(versionString: string) {
+		console.log(`Constructing version from ${versionString}`);
+
+		const match = versionString.match(VERSION_REGEX);
+
+		if( match === null || match.groups === undefined ) {
+			throw new Error("Couldn't parse version: " + versionString)
+		}
+
+		const g = match.groups;
+
+		if( g['release'] === undefined ) {
+			throw new Error("Couldn't parse version (because of the absence of a release): " + versionString)
+		}
+
+		const [ major, minor, patch ] = g['release'].split(".").map( e => Number(e) );
+
+		this.release = {
+			major: major ?? 0,
+			minor: minor ?? 0,
+			patch: patch ?? 0,
+		}
+
+		this.epoch = Number(g['epoch']);
+
+		if( g['pre'] ) {
+			this.preRelease = {
+				name: g['pre_l'],
+				version: g['pre_n'] ? Number(g['pre_n']) : undefined,
+			}
+		}
+
+		if( g['post'] ) {
+			this.postRelease = {
+				name: g['post_l'],
+				version: g['post_n'] ? Number(g['post_n']) : undefined,
+			}
+		}
+
+		if( g['dev'] ) {
+			this.dev = {
+				name: g['dev_l'],
+				version: g['dev_n'] ? Number(g['dev_n']) : undefined,
+			}
+		}
+
+		this.random_bullshit_at_the_end = g['random_bullshit'];
+	}
+
+	/**
+		* @returns the version (as as tring) in a format that can be correctly compared
+		* even if it looks goofy
+		*/
+	toComparableString() {
+		// comparing strings is annoying
+		// for example: "1.2" > "1.12", even though 12 > 2
+		//
+		// To fix that issue, we're going to have fixed-length numbers,
+		// so that comparing 1.2 and 1.12 would mean comparing
+		// "000012" > "000002", this one being correct because 1 > 0.
+
+		// pad to 8 because who in their right mind would use 8 digits for the major version
+		// (noting that some people use 4 because they use years)
+		const PAD_LENGTH = 8;
+		
+		const epoch = (this.epoch?.toString() ?? '0').padStart(PAD_LENGTH, '0');
+
+		const release_major = (this.release.major.toString() ?? '0').padStart(PAD_LENGTH, '0');
+		const release_minor = (this.release.minor.toString() ?? '0').padStart(PAD_LENGTH, '0');
+		const release_patch = (this.release.patch.toString() ?? '0').padStart(PAD_LENGTH, '0');
+		const release = `${release_major}.${release_minor}.${release_patch}`;
+
+		const prename = (this.preRelease?.name || '').padStart(PAD_LENGTH, '0');
+		const postname = (this.postRelease?.name || '').padStart(PAD_LENGTH, '0');
+		const devname = (this.dev?.name || '').padStart(PAD_LENGTH, '0');
+
+
+		const prever = (this.preRelease?.version?.toString() || '0').padStart(PAD_LENGTH, '0');
+		const postver = (this.postRelease?.version?.toString() || '0').padStart(PAD_LENGTH, '0');
+		const devver = (this.dev?.version?.toString() || '0').padStart(PAD_LENGTH, '0');
+
+		return `${epoch}!${release}.${prename}${prever}.${postname}${postver}.${devname}${devver}`;
+	}
+
+	isAbove(other: Pep440Version) {
+		return this.toComparableString() > other.toComparableString();
+	}
+
+	isBelow(other: Pep440Version) {
+		return this.toComparableString() < other.toComparableString();
+	}
+
+	isEqual(other: Pep440Version) {
+		return this.toComparableString() === other.toComparableString();
+	}
+
+	compare(other: Pep440Version) {
+		if( this.isAbove(other) ) {
+			return -1;
+		}
+		else if( this.isBelow(other) ) {
+			return 1;
+		}
+		else {
+			return 0;
+		}
+	}
+
+	/**
+		* @returns the version as a Pep440-compliant, human-readable string (e.g. "2.1.3")
+		*/
+	releaseString() {
+		let str = "";
+
+		if( this.epoch ) {
+			str += `${this.epoch}!`;
+		}
+		str += this.release.major ?? 0;
+		str += '.';
+		str += this.release.minor ?? 0;
+		str += '.';
+		str += this.release.patch ?? 0;
+
+		if(this.preRelease) {
+			str += '.';
+			if( this.preRelease.name ) {
+				str += this.preRelease.name;
+			}
+			if( this.preRelease.version ) {
+				str += this.preRelease.version;
+			}
+		}
+
+		if(this.postRelease) {
+			str += '.';
+			if( this.postRelease.name ) {
+				str += this.postRelease.name;
+			}
+			if( this.postRelease.version ) {
+				str += this.postRelease.version;
+			}
+		}
+
+		if(this.dev) {
+			str += '.';
+			if( this.dev.name ) {
+				str += this.dev.name;
+			}
+			if( this.dev.version ) {
+				str += this.dev.version;
+			}
+		}
+
+		if( this.random_bullshit_at_the_end ) {
+			str += this.random_bullshit_at_the_end;
+		}
+
+		return str;
+	}
+
+	//static fromString(...versionStrings: string[]) {
+	//	return versionStrings.map( v => new Pep440Version(v) );
+	//}
+}
+
+type OPERATOR_FUNCTION = (source: Pep440Version, target: Pep440Version) => boolean
+
+type OPERATORS_FN_type = {
+	[key: string]: OPERATOR_FUNCTION;
+};
+
+const OPERATORS_FUNCTIONS: OPERATORS_FN_type = {
+	">=": (source, target) => target.isAbove(source) || target.isEqual(source),
+	">": (source, target) => target.isAbove(source),
+	"==": (source, target) => target.isEqual(source),
+	"": (source, target) => true,
+};
+
+export class Pep440VersionRule {
+	version: Pep440Version;
+	operator: OPERATOR_FUNCTION;
+
+	constructor(version: Pep440Version, operator: string = "") {
+		this.version = version;
+		this.operator = OPERATORS_FUNCTIONS[operator];
+	}
+
+	/**
+		*/
+	getSortedMatchingVersions(versions: Pep440Version[]) {
+		const sorted = versions.sort( (a, b) => a.compare(b) );
+
+		let filtered;
+		if( typeof this.operator === "function" ) {
+			filtered = sorted.filter( v => this.operator( this.version, v ) );
+		}
+		else {
+			filtered = sorted;
+		}
+
+
+		return filtered;
+	}
+
+	static getRuleMatchingAnyVersion() {
+		return new Pep440VersionRule(new Pep440Version("0.0.0"))
+	}
+}
+
+//console.log( new Pep440Version("4!1.2.3dev2").toComparableString() )
diff --git a/static/bars.svg b/static/bars.svg
new file mode 100644
index 0000000..7cb07e6
--- /dev/null
+++ b/static/bars.svg
@@ -0,0 +1,52 @@
+
+    
+        
+        
+    
+    
+        
+        
+    
+    
+        
+        
+    
+    
+        
+        
+    
+    
+        
+        
+    
+
diff --git a/static/lib/graphology.umd.min.js b/static/lib/graphology.umd.min.js
new file mode 100644
index 0000000..08ff6bc
--- /dev/null
+++ b/static/lib/graphology.umd.min.js
@@ -0,0 +1,2 @@
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).graphology=e()}(this,(function(){"use strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,r(t,e)}function n(t){return n=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},n(t)}function r(t,e){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},r(t,e)}function i(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function o(t,e,n){return o=i()?Reflect.construct.bind():function(t,e,n){var i=[null];i.push.apply(i,e);var o=new(Function.bind.apply(t,i));return n&&r(o,n.prototype),o},o.apply(null,arguments)}function a(t){var e="function"==typeof Map?new Map:void 0;return a=function(t){if(null===t||(i=t,-1===Function.toString.call(i).indexOf("[native code]")))return t;var i;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,a)}function a(){return o(t,arguments,n(this).constructor)}return a.prototype=Object.create(t.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),r(a,t)},a(t)}function c(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}var u=function(){for(var t=arguments[0],e=1,n=arguments.length;e0&&a.length>i&&!a.warned){a.warned=!0;var u=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=t,u.type=e,u.count=a.length,c=u,console&&console.warn&&console.warn(c)}return t}function E(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function A(t,e,n){var r={fired:!1,wrapFn:void 0,target:t,type:e,listener:n},i=E.bind(r);return i.listener=n,r.wrapFn=i,i}function L(t,e,n){var r=t._events;if(void 0===r)return[];var i=r[e];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(t){for(var e=new Array(t.length),n=0;n0&&(o=e[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var c=i[t];if(void 0===c)return!1;if("function"==typeof c)v(c,this,e);else{var u=c.length,d=D(c,u);for(n=0;n=0;o--)if(n[o]===e||n[o].listener===e){a=n[o].listener,i=o;break}if(i<0)return this;0===i?n.shift():function(t,e){for(;e+1=0;r--)this.removeListener(t,e[r]);return this},m.prototype.listeners=function(t){return L(this,t,!0)},m.prototype.rawListeners=function(t){return L(this,t,!1)},m.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):S.call(t,e)},m.prototype.listenerCount=S,m.prototype.eventNames=function(){return this._eventsCount>0?g(this._events):[]},"undefined"!=typeof Symbol&&(N.prototype[Symbol.iterator]=function(){return this}),N.of=function(){var t=arguments,e=t.length,n=0;return new N((function(){return n>=e?{done:!0}:{done:!1,value:t[n++]}}))},N.empty=function(){return new N((function(){return{done:!0}}))},N.fromSequence=function(t){var e=0,n=t.length;return new N((function(){return e>=n?{done:!0}:{done:!1,value:t[e++]}}))},N.is=function(t){return t instanceof N||"object"==typeof t&&null!==t&&"function"==typeof t.next};var O=N,j={};j.ARRAY_BUFFER_SUPPORT="undefined"!=typeof ArrayBuffer,j.SYMBOL_SUPPORT="undefined"!=typeof Symbol;var C=O,M=j,z=M.ARRAY_BUFFER_SUPPORT,W=M.SYMBOL_SUPPORT;var P=function(t){var e=function(t){return"string"==typeof t||Array.isArray(t)||z&&ArrayBuffer.isView(t)?C.fromSequence(t):"object"!=typeof t||null===t?null:W&&"function"==typeof t[Symbol.iterator]?t[Symbol.iterator]():"function"==typeof t.next?t:null}(t);if(!e)throw new Error("obliterator: target is not iterable nor a valid iterator.");return e},R=P,K=function(t,e){for(var n,r=arguments.length>1?e:1/0,i=r!==1/0?new Array(r):[],o=0,a=R(t);;){if(o===r)return i;if((n=a.next()).done)return o!==e&&(i.length=o),i;i[o++]=n.value}},T=function(t){function n(e){var n;return(n=t.call(this)||this).name="GraphError",n.message=e,n}return e(n,t),n}(a(Error)),B=function(t){function n(e){var r;return(r=t.call(this,e)||this).name="InvalidArgumentsGraphError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(c(r),n.prototype.constructor),r}return e(n,t),n}(T),F=function(t){function n(e){var r;return(r=t.call(this,e)||this).name="NotFoundGraphError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(c(r),n.prototype.constructor),r}return e(n,t),n}(T),I=function(t){function n(e){var r;return(r=t.call(this,e)||this).name="UsageGraphError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(c(r),n.prototype.constructor),r}return e(n,t),n}(T);function Y(t,e){this.key=t,this.attributes=e,this.clear()}function q(t,e){this.key=t,this.attributes=e,this.clear()}function J(t,e){this.key=t,this.attributes=e,this.clear()}function V(t,e,n,r,i){this.key=e,this.attributes=i,this.undirected=t,this.source=n,this.target=r}Y.prototype.clear=function(){this.inDegree=0,this.outDegree=0,this.undirectedDegree=0,this.undirectedLoops=0,this.directedLoops=0,this.in={},this.out={},this.undirected={}},q.prototype.clear=function(){this.inDegree=0,this.outDegree=0,this.directedLoops=0,this.in={},this.out={}},J.prototype.clear=function(){this.undirectedDegree=0,this.undirectedLoops=0,this.undirected={}},V.prototype.attach=function(){var t="out",e="in";this.undirected&&(t=e="undirected");var n=this.source.key,r=this.target.key;this.source[t][r]=this,this.undirected&&n===r||(this.target[e][n]=this)},V.prototype.attachMulti=function(){var t="out",e="in",n=this.source.key,r=this.target.key;this.undirected&&(t=e="undirected");var i=this.source[t],o=i[r];if(void 0===o)return i[r]=this,void(this.undirected&&n===r||(this.target[e][n]=this));o.previous=this,this.next=o,i[r]=this,this.target[e][n]=this},V.prototype.detach=function(){var t=this.source.key,e=this.target.key,n="out",r="in";this.undirected&&(n=r="undirected"),delete this.source[n][e],delete this.target[r][t]},V.prototype.detachMulti=function(){var t=this.source.key,e=this.target.key,n="out",r="in";this.undirected&&(n=r="undirected"),void 0===this.previous?void 0===this.next?(delete this.source[n][e],delete this.target[r][t]):(this.next.previous=void 0,this.source[n][e]=this.next,this.target[r][t]=this.next):(this.previous.next=this.next,void 0!==this.next&&(this.next.previous=this.previous))};function H(t,e,n,r,i,o,a){var c,u,d,s;if(r=""+r,0===n){if(!(c=t._nodes.get(r)))throw new F("Graph.".concat(e,': could not find the "').concat(r,'" node in the graph.'));d=i,s=o}else if(3===n){if(i=""+i,!(u=t._edges.get(i)))throw new F("Graph.".concat(e,': could not find the "').concat(i,'" edge in the graph.'));var h=u.source.key,p=u.target.key;if(r===h)c=u.target;else{if(r!==p)throw new F("Graph.".concat(e,': the "').concat(r,'" node is not attached to the "').concat(i,'" edge (').concat(h,", ").concat(p,")."));c=u.source}d=o,s=a}else{if(!(u=t._edges.get(r)))throw new F("Graph.".concat(e,': could not find the "').concat(r,'" edge in the graph.'));c=1===n?u.source:u.target,d=i,s=o}return[c,d,s]}var Q=[{name:function(t){return"get".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=H(this,e,n,t,r,i),a=o[0],c=o[1];return a.attributes[c]}}},{name:function(t){return"get".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){return H(this,e,n,t,r)[0].attributes}}},{name:function(t){return"has".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=H(this,e,n,t,r,i),a=o[0],c=o[1];return a.attributes.hasOwnProperty(c)}}},{name:function(t){return"set".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i,o){var a=H(this,e,n,t,r,i,o),c=a[0],u=a[1],d=a[2];return c.attributes[u]=d,this.emit("nodeAttributesUpdated",{key:c.key,type:"set",attributes:c.attributes,name:u}),this}}},{name:function(t){return"update".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i,o){var a=H(this,e,n,t,r,i,o),c=a[0],u=a[1],d=a[2];if("function"!=typeof d)throw new B("Graph.".concat(e,": updater should be a function."));var s=c.attributes,h=d(s[u]);return s[u]=h,this.emit("nodeAttributesUpdated",{key:c.key,type:"set",attributes:c.attributes,name:u}),this}}},{name:function(t){return"remove".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=H(this,e,n,t,r,i),a=o[0],c=o[1];return delete a.attributes[c],this.emit("nodeAttributesUpdated",{key:a.key,type:"remove",attributes:a.attributes,name:c}),this}}},{name:function(t){return"replace".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=H(this,e,n,t,r,i),a=o[0],c=o[1];if(!s(c))throw new B("Graph.".concat(e,": provided attributes are not a plain object."));return a.attributes=c,this.emit("nodeAttributesUpdated",{key:a.key,type:"replace",attributes:a.attributes}),this}}},{name:function(t){return"merge".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=H(this,e,n,t,r,i),a=o[0],c=o[1];if(!s(c))throw new B("Graph.".concat(e,": provided attributes are not a plain object."));return u(a.attributes,c),this.emit("nodeAttributesUpdated",{key:a.key,type:"merge",attributes:a.attributes,data:c}),this}}},{name:function(t){return"update".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o=H(this,e,n,t,r,i),a=o[0],c=o[1];if("function"!=typeof c)throw new B("Graph.".concat(e,": provided updater is not a function."));return a.attributes=c(a.attributes),this.emit("nodeAttributesUpdated",{key:a.key,type:"update",attributes:a.attributes}),this}}}];var X=[{name:function(t){return"get".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=d(this,o,a,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return i.attributes[r]}}},{name:function(t){return"get".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t){var r;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>1){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var i=""+t,o=""+arguments[1];if(!(r=d(this,i,o,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(i,'" - "').concat(o,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(r=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return r.attributes}}},{name:function(t){return"has".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=d(this,o,a,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return i.attributes.hasOwnProperty(r)}}},{name:function(t){return"set".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>3){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var a=""+t,c=""+r;if(r=arguments[2],i=arguments[3],!(o=d(this,a,c,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(a,'" - "').concat(c,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(o=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return o.attributes[r]=i,this.emit("edgeAttributesUpdated",{key:o.key,type:"set",attributes:o.attributes,name:r}),this}}},{name:function(t){return"update".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r,i){var o;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>3){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var a=""+t,c=""+r;if(r=arguments[2],i=arguments[3],!(o=d(this,a,c,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(a,'" - "').concat(c,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(o=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if("function"!=typeof i)throw new B("Graph.".concat(e,": updater should be a function."));return o.attributes[r]=i(o.attributes[r]),this.emit("edgeAttributesUpdated",{key:o.key,type:"set",attributes:o.attributes,name:r}),this}}},{name:function(t){return"remove".concat(t,"Attribute")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=d(this,o,a,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}return delete i.attributes[r],this.emit("edgeAttributesUpdated",{key:i.key,type:"remove",attributes:i.attributes,name:r}),this}}},{name:function(t){return"replace".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=d(this,o,a,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if(!s(r))throw new B("Graph.".concat(e,": provided attributes are not a plain object."));return i.attributes=r,this.emit("edgeAttributesUpdated",{key:i.key,type:"replace",attributes:i.attributes}),this}}},{name:function(t){return"merge".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=d(this,o,a,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if(!s(r))throw new B("Graph.".concat(e,": provided attributes are not a plain object."));return u(i.attributes,r),this.emit("edgeAttributesUpdated",{key:i.key,type:"merge",attributes:i.attributes,data:r}),this}}},{name:function(t){return"update".concat(t,"Attributes")},attacher:function(t,e,n){t.prototype[e]=function(t,r){var i;if("mixed"!==this.type&&"mixed"!==n&&n!==this.type)throw new I("Graph.".concat(e,": cannot find this type of edges in your ").concat(this.type," graph."));if(arguments.length>2){if(this.multi)throw new I("Graph.".concat(e,": cannot use a {source,target} combo when asking about an edge's attributes in a MultiGraph since we cannot infer the one you want information about."));var o=""+t,a=""+r;if(r=arguments[2],!(i=d(this,o,a,n)))throw new F("Graph.".concat(e,': could not find an edge for the given path ("').concat(o,'" - "').concat(a,'").'))}else{if("mixed"!==n)throw new I("Graph.".concat(e,": calling this method with only a key (vs. a source and target) does not make sense since an edge with this key could have the other type."));if(t=""+t,!(i=this._edges.get(t)))throw new F("Graph.".concat(e,': could not find the "').concat(t,'" edge in the graph.'))}if("function"!=typeof r)throw new B("Graph.".concat(e,": provided updater is not a function."));return i.attributes=r(i.attributes),this.emit("edgeAttributesUpdated",{key:i.key,type:"update",attributes:i.attributes}),this}}}];var Z=O,$=P,tt=function(){var t=arguments,e=null,n=-1;return new Z((function(){for(var r=null;;){if(null===e){if(++n>=t.length)return{done:!0};e=$(t[n])}if(!0!==(r=e.next()).done)break;e=null}return r}))},et=[{name:"edges",type:"mixed"},{name:"inEdges",type:"directed",direction:"in"},{name:"outEdges",type:"directed",direction:"out"},{name:"inboundEdges",type:"mixed",direction:"in"},{name:"outboundEdges",type:"mixed",direction:"out"},{name:"directedEdges",type:"directed"},{name:"undirectedEdges",type:"undirected"}];function nt(t,e,n,r){var i=!1;for(var o in e)if(o!==r){var a=e[o];if(i=n(a.key,a.attributes,a.source.key,a.target.key,a.source.attributes,a.target.attributes,a.undirected),t&&i)return a.key}}function rt(t,e,n,r){var i,o,a,c=!1;for(var u in e)if(u!==r){i=e[u];do{if(o=i.source,a=i.target,c=n(i.key,i.attributes,o.key,a.key,o.attributes,a.attributes,i.undirected),t&&c)return i.key;i=i.next}while(void 0!==i)}}function it(t,e){var n,r=Object.keys(t),i=r.length,o=0;return new O((function(){do{if(n)n=n.next;else{if(o>=i)return{done:!0};var a=r[o++];if(a===e){n=void 0;continue}n=t[a]}}while(!n);return{done:!1,value:{edge:n.key,attributes:n.attributes,source:n.source.key,target:n.target.key,sourceAttributes:n.source.attributes,targetAttributes:n.target.attributes,undirected:n.undirected}}}))}function ot(t,e,n,r){var i=e[n];if(i){var o=i.source,a=i.target;return r(i.key,i.attributes,o.key,a.key,o.attributes,a.attributes,i.undirected)&&t?i.key:void 0}}function at(t,e,n,r){var i=e[n];if(i){var o=!1;do{if(o=r(i.key,i.attributes,i.source.key,i.target.key,i.source.attributes,i.target.attributes,i.undirected),t&&o)return i.key;i=i.next}while(void 0!==i)}}function ct(t,e){var n=t[e];return void 0!==n.next?new O((function(){if(!n)return{done:!0};var t={edge:n.key,attributes:n.attributes,source:n.source.key,target:n.target.key,sourceAttributes:n.source.attributes,targetAttributes:n.target.attributes,undirected:n.undirected};return n=n.next,{done:!1,value:t}})):O.of({edge:n.key,attributes:n.attributes,source:n.source.key,target:n.target.key,sourceAttributes:n.source.attributes,targetAttributes:n.target.attributes,undirected:n.undirected})}function ut(t,e){if(0===t.size)return[];if("mixed"===e||e===t.type)return"function"==typeof Array.from?Array.from(t._edges.keys()):K(t._edges.keys(),t._edges.size);for(var n,r,i="undirected"===e?t.undirectedSize:t.directedSize,o=new Array(i),a="undirected"===e,c=t._edges.values(),u=0;!0!==(n=c.next()).done;)(r=n.value).undirected===a&&(o[u++]=r.key);return o}function dt(t,e,n,r){if(0!==e.size)for(var i,o,a="mixed"!==n&&n!==e.type,c="undirected"===n,u=!1,d=e._edges.values();!0!==(i=d.next()).done;)if(o=i.value,!a||o.undirected===c){var s=o,h=s.key,p=s.attributes,f=s.source,l=s.target;if(u=r(h,p,f.key,l.key,f.attributes,l.attributes,o.undirected),t&&u)return h}}function st(t,e){if(0===t.size)return O.empty();var n="mixed"!==e&&e!==t.type,r="undirected"===e,i=t._edges.values();return new O((function(){for(var t,e;;){if((t=i.next()).done)return t;if(e=t.value,!n||e.undirected===r)break}return{value:{edge:e.key,attributes:e.attributes,source:e.source.key,target:e.target.key,sourceAttributes:e.source.attributes,targetAttributes:e.target.attributes,undirected:e.undirected},done:!1}}))}function ht(t,e,n,r,i,o){var a,c=e?rt:nt;if("undirected"!==n){if("out"!==r&&(a=c(t,i.in,o),t&&a))return a;if("in"!==r&&(a=c(t,i.out,o,r?void 0:i.key),t&&a))return a}if("directed"!==n&&(a=c(t,i.undirected,o),t&&a))return a}function pt(t,e,n,r){var i=[];return ht(!1,t,e,n,r,(function(t){i.push(t)})),i}function ft(t,e,n){var r=O.empty();return"undirected"!==t&&("out"!==e&&void 0!==n.in&&(r=tt(r,it(n.in))),"in"!==e&&void 0!==n.out&&(r=tt(r,it(n.out,e?void 0:n.key)))),"directed"!==t&&void 0!==n.undirected&&(r=tt(r,it(n.undirected))),r}function lt(t,e,n,r,i,o,a){var c,u=n?at:ot;if("undirected"!==e){if(void 0!==i.in&&"out"!==r&&(c=u(t,i.in,o,a),t&&c))return c;if(void 0!==i.out&&"in"!==r&&(r||i.key!==o)&&(c=u(t,i.out,o,a),t&&c))return c}if("directed"!==e&&void 0!==i.undirected&&(c=u(t,i.undirected,o,a),t&&c))return c}function gt(t,e,n,r,i){var o=[];return lt(!1,t,e,n,r,i,(function(t){o.push(t)})),o}function yt(t,e,n,r){var i=O.empty();return"undirected"!==t&&(void 0!==n.in&&"out"!==e&&r in n.in&&(i=tt(i,ct(n.in,r))),void 0!==n.out&&"in"!==e&&r in n.out&&(e||n.key!==r)&&(i=tt(i,ct(n.out,r)))),"directed"!==t&&void 0!==n.undirected&&r in n.undirected&&(i=tt(i,ct(n.undirected,r))),i}var wt=[{name:"neighbors",type:"mixed"},{name:"inNeighbors",type:"directed",direction:"in"},{name:"outNeighbors",type:"directed",direction:"out"},{name:"inboundNeighbors",type:"mixed",direction:"in"},{name:"outboundNeighbors",type:"mixed",direction:"out"},{name:"directedNeighbors",type:"directed"},{name:"undirectedNeighbors",type:"undirected"}];function vt(){this.A=null,this.B=null}function bt(t,e,n,r,i){for(var o in r){var a=r[o],c=a.source,u=a.target,d=c===n?u:c;if(!e||!e.has(d.key)){var s=i(d.key,d.attributes);if(t&&s)return d.key}}}function mt(t,e,n,r,i){if("mixed"!==e){if("undirected"===e)return bt(t,null,r,r.undirected,i);if("string"==typeof n)return bt(t,null,r,r[n],i)}var o,a=new vt;if("undirected"!==e){if("out"!==n){if(o=bt(t,null,r,r.in,i),t&&o)return o;a.wrap(r.in)}if("in"!==n){if(o=bt(t,a,r,r.out,i),t&&o)return o;a.wrap(r.out)}}if("directed"!==e&&(o=bt(t,a,r,r.undirected,i),t&&o))return o}function kt(t,e,n){var r=Object.keys(n),i=r.length,o=0;return new O((function(){var a=null;do{if(o>=i)return t&&t.wrap(n),{done:!0};var c=n[r[o++]],u=c.source,d=c.target;a=u===e?d:u,t&&t.has(a.key)&&(a=null)}while(null===a);return{done:!1,value:{neighbor:a.key,attributes:a.attributes}}}))}function _t(t,e){var n=e.name,r=e.type,i=e.direction;t.prototype[n]=function(t){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return[];t=""+t;var e=this._nodes.get(t);if(void 0===e)throw new F("Graph.".concat(n,': could not find the "').concat(t,'" node in the graph.'));return function(t,e,n){if("mixed"!==t){if("undirected"===t)return Object.keys(n.undirected);if("string"==typeof e)return Object.keys(n[e])}var r=[];return mt(!1,t,e,n,(function(t){r.push(t)})),r}("mixed"===r?this.type:r,i,e)}}function Gt(t,e){var n=e.name,r=e.type,i=e.direction,o=n.slice(0,-1)+"Entries";t.prototype[o]=function(t){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return O.empty();t=""+t;var e=this._nodes.get(t);if(void 0===e)throw new F("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return function(t,e,n){if("mixed"!==t){if("undirected"===t)return kt(null,n,n.undirected);if("string"==typeof e)return kt(null,n,n[e])}var r=O.empty(),i=new vt;return"undirected"!==t&&("out"!==e&&(r=tt(r,kt(i,n,n.in))),"in"!==e&&(r=tt(r,kt(i,n,n.out)))),"directed"!==t&&(r=tt(r,kt(i,n,n.undirected))),r}("mixed"===r?this.type:r,i,e)}}function xt(t,e,n,r,i){for(var o,a,c,u,d,s,h,p=r._nodes.values(),f=r.type;!0!==(o=p.next()).done;){var l=!1;if(a=o.value,"undirected"!==f)for(c in u=a.out){d=u[c];do{if(s=d.target,l=!0,h=i(a.key,s.key,a.attributes,s.attributes,d.key,d.attributes,d.undirected),t&&h)return d;d=d.next}while(d)}if("directed"!==f)for(c in u=a.undirected)if(!(e&&a.key>c)){d=u[c];do{if((s=d.target).key!==c&&(s=d.source),l=!0,h=i(a.key,s.key,a.attributes,s.attributes,d.key,d.attributes,d.undirected),t&&h)return d;d=d.next}while(d)}if(n&&!l&&(h=i(a.key,null,a.attributes,null,null,null,null),t&&h))return null}}function Et(t){if(!s(t))throw new B('Graph.import: invalid serialized node. A serialized node should be a plain object with at least a "key" property.');if(!("key"in t))throw new B("Graph.import: serialized node is missing its key.");if("attributes"in t&&(!s(t.attributes)||null===t.attributes))throw new B("Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.")}function At(t){if(!s(t))throw new B('Graph.import: invalid serialized edge. A serialized edge should be a plain object with at least a "source" & "target" property.');if(!("source"in t))throw new B("Graph.import: serialized edge is missing its source.");if(!("target"in t))throw new B("Graph.import: serialized edge is missing its target.");if("attributes"in t&&(!s(t.attributes)||null===t.attributes))throw new B("Graph.import: invalid attributes. Attributes should be a plain object, null or omitted.");if("undirected"in t&&"boolean"!=typeof t.undirected)throw new B("Graph.import: invalid undirectedness information. Undirected should be boolean or omitted.")}vt.prototype.wrap=function(t){null===this.A?this.A=t:null===this.B&&(this.B=t)},vt.prototype.has=function(t){return null!==this.A&&t in this.A||null!==this.B&&t in this.B};var Lt,St=(Lt=255&Math.floor(256*Math.random()),function(){return Lt++}),Dt=new Set(["directed","undirected","mixed"]),Ut=new Set(["domain","_events","_eventsCount","_maxListeners"]),Nt={allowSelfLoops:!0,multi:!1,type:"mixed"};function Ot(t,e,n){var r=new t.NodeDataClass(e,n);return t._nodes.set(e,r),t.emit("nodeAdded",{key:e,attributes:n}),r}function jt(t,e,n,r,i,o,a,c){if(!r&&"undirected"===t.type)throw new I("Graph.".concat(e,": you cannot add a directed edge to an undirected graph. Use the #.addEdge or #.addUndirectedEdge instead."));if(r&&"directed"===t.type)throw new I("Graph.".concat(e,": you cannot add an undirected edge to a directed graph. Use the #.addEdge or #.addDirectedEdge instead."));if(c&&!s(c))throw new B("Graph.".concat(e,': invalid attributes. Expecting an object but got "').concat(c,'"'));if(o=""+o,a=""+a,c=c||{},!t.allowSelfLoops&&o===a)throw new I("Graph.".concat(e,': source & target are the same ("').concat(o,"\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));var u=t._nodes.get(o),d=t._nodes.get(a);if(!u)throw new F("Graph.".concat(e,': source node "').concat(o,'" not found.'));if(!d)throw new F("Graph.".concat(e,': target node "').concat(a,'" not found.'));var h={key:null,undirected:r,source:o,target:a,attributes:c};if(n)i=t._edgeKeyGenerator();else if(i=""+i,t._edges.has(i))throw new I("Graph.".concat(e,': the "').concat(i,'" edge already exists in the graph.'));if(!t.multi&&(r?void 0!==u.undirected[a]:void 0!==u.out[a]))throw new I("Graph.".concat(e,': an edge linking "').concat(o,'" to "').concat(a,"\" already exists. If you really want to add multiple edges linking those nodes, you should create a multi graph by using the 'multi' option."));var p=new V(r,i,u,d,c);t._edges.set(i,p);var f=o===a;return r?(u.undirectedDegree++,d.undirectedDegree++,f&&(u.undirectedLoops++,t._undirectedSelfLoopCount++)):(u.outDegree++,d.inDegree++,f&&(u.directedLoops++,t._directedSelfLoopCount++)),t.multi?p.attachMulti():p.attach(),r?t._undirectedSize++:t._directedSize++,h.key=i,t.emit("edgeAdded",h),i}function Ct(t,e,n,r,i,o,a,c,d){if(!r&&"undirected"===t.type)throw new I("Graph.".concat(e,": you cannot merge/update a directed edge to an undirected graph. Use the #.mergeEdge/#.updateEdge or #.addUndirectedEdge instead."));if(r&&"directed"===t.type)throw new I("Graph.".concat(e,": you cannot merge/update an undirected edge to a directed graph. Use the #.mergeEdge/#.updateEdge or #.addDirectedEdge instead."));if(c)if(d){if("function"!=typeof c)throw new B("Graph.".concat(e,': invalid updater function. Expecting a function but got "').concat(c,'"'))}else if(!s(c))throw new B("Graph.".concat(e,': invalid attributes. Expecting an object but got "').concat(c,'"'));var h;if(o=""+o,a=""+a,d&&(h=c,c=void 0),!t.allowSelfLoops&&o===a)throw new I("Graph.".concat(e,': source & target are the same ("').concat(o,"\"), thus creating a loop explicitly forbidden by this graph 'allowSelfLoops' option set to false."));var p,f,l=t._nodes.get(o),g=t._nodes.get(a);if(!n&&(p=t._edges.get(i))){if(!(p.source.key===o&&p.target.key===a||r&&p.source.key===a&&p.target.key===o))throw new I("Graph.".concat(e,': inconsistency detected when attempting to merge the "').concat(i,'" edge with "').concat(o,'" source & "').concat(a,'" target vs. ("').concat(p.source.key,'", "').concat(p.target.key,'").'));f=p}if(f||t.multi||!l||(f=r?l.undirected[a]:l.out[a]),f){var y=[f.key,!1,!1,!1];if(d?!h:!c)return y;if(d){var w=f.attributes;f.attributes=h(w),t.emit("edgeAttributesUpdated",{type:"replace",key:f.key,attributes:f.attributes})}else u(f.attributes,c),t.emit("edgeAttributesUpdated",{type:"merge",key:f.key,attributes:f.attributes,data:c});return y}c=c||{},d&&h&&(c=h(c));var v={key:null,undirected:r,source:o,target:a,attributes:c};if(n)i=t._edgeKeyGenerator();else if(i=""+i,t._edges.has(i))throw new I("Graph.".concat(e,': the "').concat(i,'" edge already exists in the graph.'));var b=!1,m=!1;l||(l=Ot(t,o,{}),b=!0,o===a&&(g=l,m=!0)),g||(g=Ot(t,a,{}),m=!0),p=new V(r,i,l,g,c),t._edges.set(i,p);var k=o===a;return r?(l.undirectedDegree++,g.undirectedDegree++,k&&(l.undirectedLoops++,t._undirectedSelfLoopCount++)):(l.outDegree++,g.inDegree++,k&&(l.directedLoops++,t._directedSelfLoopCount++)),t.multi?p.attachMulti():p.attach(),r?t._undirectedSize++:t._directedSize++,v.key=i,t.emit("edgeAdded",v),[i,!0,b,m]}function Mt(t,e){t._edges.delete(e.key);var n=e.source,r=e.target,i=e.attributes,o=e.undirected,a=n===r;o?(n.undirectedDegree--,r.undirectedDegree--,a&&(n.undirectedLoops--,t._undirectedSelfLoopCount--)):(n.outDegree--,r.inDegree--,a&&(n.directedLoops--,t._directedSelfLoopCount--)),t.multi?e.detachMulti():e.detach(),o?t._undirectedSize--:t._directedSize--,t.emit("edgeDropped",{key:e.key,attributes:i,source:n.key,target:r.key,undirected:o})}var zt=function(n){function r(t){var e;if(e=n.call(this)||this,"boolean"!=typeof(t=u({},Nt,t)).multi)throw new B("Graph.constructor: invalid 'multi' option. Expecting a boolean but got \"".concat(t.multi,'".'));if(!Dt.has(t.type))throw new B('Graph.constructor: invalid \'type\' option. Should be one of "mixed", "directed" or "undirected" but got "'.concat(t.type,'".'));if("boolean"!=typeof t.allowSelfLoops)throw new B("Graph.constructor: invalid 'allowSelfLoops' option. Expecting a boolean but got \"".concat(t.allowSelfLoops,'".'));var r="mixed"===t.type?Y:"directed"===t.type?q:J;p(c(e),"NodeDataClass",r);var i="geid_"+St()+"_",o=0;return p(c(e),"_attributes",{}),p(c(e),"_nodes",new Map),p(c(e),"_edges",new Map),p(c(e),"_directedSize",0),p(c(e),"_undirectedSize",0),p(c(e),"_directedSelfLoopCount",0),p(c(e),"_undirectedSelfLoopCount",0),p(c(e),"_edgeKeyGenerator",(function(){var t;do{t=i+o++}while(e._edges.has(t));return t})),p(c(e),"_options",t),Ut.forEach((function(t){return p(c(e),t,e[t])})),f(c(e),"order",(function(){return e._nodes.size})),f(c(e),"size",(function(){return e._edges.size})),f(c(e),"directedSize",(function(){return e._directedSize})),f(c(e),"undirectedSize",(function(){return e._undirectedSize})),f(c(e),"selfLoopCount",(function(){return e._directedSelfLoopCount+e._undirectedSelfLoopCount})),f(c(e),"directedSelfLoopCount",(function(){return e._directedSelfLoopCount})),f(c(e),"undirectedSelfLoopCount",(function(){return e._undirectedSelfLoopCount})),f(c(e),"multi",e._options.multi),f(c(e),"type",e._options.type),f(c(e),"allowSelfLoops",e._options.allowSelfLoops),f(c(e),"implementation",(function(){return"graphology"})),e}e(r,n);var i=r.prototype;return i._resetInstanceCounters=function(){this._directedSize=0,this._undirectedSize=0,this._directedSelfLoopCount=0,this._undirectedSelfLoopCount=0},i.hasNode=function(t){return this._nodes.has(""+t)},i.hasDirectedEdge=function(t,e){if("undirected"===this.type)return!1;if(1===arguments.length){var n=""+t,r=this._edges.get(n);return!!r&&!r.undirected}if(2===arguments.length){t=""+t,e=""+e;var i=this._nodes.get(t);return!!i&&i.out.hasOwnProperty(e)}throw new B("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length,", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."))},i.hasUndirectedEdge=function(t,e){if("directed"===this.type)return!1;if(1===arguments.length){var n=""+t,r=this._edges.get(n);return!!r&&r.undirected}if(2===arguments.length){t=""+t,e=""+e;var i=this._nodes.get(t);return!!i&&i.undirected.hasOwnProperty(e)}throw new B("Graph.hasDirectedEdge: invalid arity (".concat(arguments.length,", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."))},i.hasEdge=function(t,e){if(1===arguments.length){var n=""+t;return this._edges.has(n)}if(2===arguments.length){t=""+t,e=""+e;var r=this._nodes.get(t);return!!r&&(void 0!==r.out&&r.out.hasOwnProperty(e)||void 0!==r.undirected&&r.undirected.hasOwnProperty(e))}throw new B("Graph.hasEdge: invalid arity (".concat(arguments.length,", instead of 1 or 2). You can either ask for an edge id or for the existence of an edge between a source & a target."))},i.directedEdge=function(t,e){if("undirected"!==this.type){if(t=""+t,e=""+e,this.multi)throw new I("Graph.directedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.directedEdges instead.");var n=this._nodes.get(t);if(!n)throw new F('Graph.directedEdge: could not find the "'.concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F('Graph.directedEdge: could not find the "'.concat(e,'" target node in the graph.'));var r=n.out&&n.out[e]||void 0;return r?r.key:void 0}},i.undirectedEdge=function(t,e){if("directed"!==this.type){if(t=""+t,e=""+e,this.multi)throw new I("Graph.undirectedEdge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.undirectedEdges instead.");var n=this._nodes.get(t);if(!n)throw new F('Graph.undirectedEdge: could not find the "'.concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F('Graph.undirectedEdge: could not find the "'.concat(e,'" target node in the graph.'));var r=n.undirected&&n.undirected[e]||void 0;return r?r.key:void 0}},i.edge=function(t,e){if(this.multi)throw new I("Graph.edge: this method is irrelevant with multigraphs since there might be multiple edges between source & target. See #.edges instead.");t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.edge: could not find the "'.concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F('Graph.edge: could not find the "'.concat(e,'" target node in the graph.'));var r=n.out&&n.out[e]||n.undirected&&n.undirected[e]||void 0;if(r)return r.key},i.areDirectedNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areDirectedNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&(e in n.in||e in n.out)},i.areOutNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areOutNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.out},i.areInNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areInNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.in},i.areUndirectedNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areUndirectedNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"directed"!==this.type&&e in n.undirected},i.areNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&(e in n.in||e in n.out)||"directed"!==this.type&&e in n.undirected},i.areInboundNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areInboundNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.in||"directed"!==this.type&&e in n.undirected},i.areOutboundNeighbors=function(t,e){t=""+t,e=""+e;var n=this._nodes.get(t);if(!n)throw new F('Graph.areOutboundNeighbors: could not find the "'.concat(t,'" node in the graph.'));return"undirected"!==this.type&&e in n.out||"directed"!==this.type&&e in n.undirected},i.inDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.inDegree: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.inDegree},i.outDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.outDegree: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.outDegree},i.directedDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.directedDegree: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.inDegree+e.outDegree},i.undirectedDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.undirectedDegree: could not find the "'.concat(t,'" node in the graph.'));return"directed"===this.type?0:e.undirectedDegree},i.inboundDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.inboundDegree: could not find the "'.concat(t,'" node in the graph.'));var n=0;return"directed"!==this.type&&(n+=e.undirectedDegree),"undirected"!==this.type&&(n+=e.inDegree),n},i.outboundDegree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.outboundDegree: could not find the "'.concat(t,'" node in the graph.'));var n=0;return"directed"!==this.type&&(n+=e.undirectedDegree),"undirected"!==this.type&&(n+=e.outDegree),n},i.degree=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.degree: could not find the "'.concat(t,'" node in the graph.'));var n=0;return"directed"!==this.type&&(n+=e.undirectedDegree),"undirected"!==this.type&&(n+=e.inDegree+e.outDegree),n},i.inDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.inDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.inDegree-e.directedLoops},i.outDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.outDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.outDegree-e.directedLoops},i.directedDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.directedDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));return"undirected"===this.type?0:e.inDegree+e.outDegree-2*e.directedLoops},i.undirectedDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.undirectedDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));return"directed"===this.type?0:e.undirectedDegree-2*e.undirectedLoops},i.inboundDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.inboundDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));var n=0,r=0;return"directed"!==this.type&&(n+=e.undirectedDegree,r+=2*e.undirectedLoops),"undirected"!==this.type&&(n+=e.inDegree,r+=e.directedLoops),n-r},i.outboundDegreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.outboundDegreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));var n=0,r=0;return"directed"!==this.type&&(n+=e.undirectedDegree,r+=2*e.undirectedLoops),"undirected"!==this.type&&(n+=e.outDegree,r+=e.directedLoops),n-r},i.degreeWithoutSelfLoops=function(t){t=""+t;var e=this._nodes.get(t);if(!e)throw new F('Graph.degreeWithoutSelfLoops: could not find the "'.concat(t,'" node in the graph.'));var n=0,r=0;return"directed"!==this.type&&(n+=e.undirectedDegree,r+=2*e.undirectedLoops),"undirected"!==this.type&&(n+=e.inDegree+e.outDegree,r+=2*e.directedLoops),n-r},i.source=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new F('Graph.source: could not find the "'.concat(t,'" edge in the graph.'));return e.source.key},i.target=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new F('Graph.target: could not find the "'.concat(t,'" edge in the graph.'));return e.target.key},i.extremities=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new F('Graph.extremities: could not find the "'.concat(t,'" edge in the graph.'));return[e.source.key,e.target.key]},i.opposite=function(t,e){t=""+t,e=""+e;var n=this._edges.get(e);if(!n)throw new F('Graph.opposite: could not find the "'.concat(e,'" edge in the graph.'));var r=n.source.key,i=n.target.key;if(t===r)return i;if(t===i)return r;throw new F('Graph.opposite: the "'.concat(t,'" node is not attached to the "').concat(e,'" edge (').concat(r,", ").concat(i,")."))},i.hasExtremity=function(t,e){t=""+t,e=""+e;var n=this._edges.get(t);if(!n)throw new F('Graph.hasExtremity: could not find the "'.concat(t,'" edge in the graph.'));return n.source.key===e||n.target.key===e},i.isUndirected=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new F('Graph.isUndirected: could not find the "'.concat(t,'" edge in the graph.'));return e.undirected},i.isDirected=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new F('Graph.isDirected: could not find the "'.concat(t,'" edge in the graph.'));return!e.undirected},i.isSelfLoop=function(t){t=""+t;var e=this._edges.get(t);if(!e)throw new F('Graph.isSelfLoop: could not find the "'.concat(t,'" edge in the graph.'));return e.source===e.target},i.addNode=function(t,e){var n=function(t,e,n){if(n&&!s(n))throw new B('Graph.addNode: invalid attributes. Expecting an object but got "'.concat(n,'"'));if(e=""+e,n=n||{},t._nodes.has(e))throw new I('Graph.addNode: the "'.concat(e,'" node already exist in the graph.'));var r=new t.NodeDataClass(e,n);return t._nodes.set(e,r),t.emit("nodeAdded",{key:e,attributes:n}),r}(this,t,e);return n.key},i.mergeNode=function(t,e){if(e&&!s(e))throw new B('Graph.mergeNode: invalid attributes. Expecting an object but got "'.concat(e,'"'));t=""+t,e=e||{};var n=this._nodes.get(t);return n?(e&&(u(n.attributes,e),this.emit("nodeAttributesUpdated",{type:"merge",key:t,attributes:n.attributes,data:e})),[t,!1]):(n=new this.NodeDataClass(t,e),this._nodes.set(t,n),this.emit("nodeAdded",{key:t,attributes:e}),[t,!0])},i.updateNode=function(t,e){if(e&&"function"!=typeof e)throw new B('Graph.updateNode: invalid updater function. Expecting a function but got "'.concat(e,'"'));t=""+t;var n=this._nodes.get(t);if(n){if(e){var r=n.attributes;n.attributes=e(r),this.emit("nodeAttributesUpdated",{type:"replace",key:t,attributes:n.attributes})}return[t,!1]}var i=e?e({}):{};return n=new this.NodeDataClass(t,i),this._nodes.set(t,n),this.emit("nodeAdded",{key:t,attributes:i}),[t,!0]},i.dropNode=function(t){t=""+t;var e,n=this._nodes.get(t);if(!n)throw new F('Graph.dropNode: could not find the "'.concat(t,'" node in the graph.'));if("undirected"!==this.type){for(var r in n.out){e=n.out[r];do{Mt(this,e),e=e.next}while(e)}for(var i in n.in){e=n.in[i];do{Mt(this,e),e=e.next}while(e)}}if("directed"!==this.type)for(var o in n.undirected){e=n.undirected[o];do{Mt(this,e),e=e.next}while(e)}this._nodes.delete(t),this.emit("nodeDropped",{key:t,attributes:n.attributes})},i.dropEdge=function(t){var e;if(arguments.length>1){var n=""+arguments[0],r=""+arguments[1];if(!(e=d(this,n,r,this.type)))throw new F('Graph.dropEdge: could not find the "'.concat(n,'" -> "').concat(r,'" edge in the graph.'))}else if(t=""+t,!(e=this._edges.get(t)))throw new F('Graph.dropEdge: could not find the "'.concat(t,'" edge in the graph.'));return Mt(this,e),this},i.dropDirectedEdge=function(t,e){if(arguments.length<2)throw new I("Graph.dropDirectedEdge: it does not make sense to try and drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.");if(this.multi)throw new I("Graph.dropDirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.");var n=d(this,t=""+t,e=""+e,"directed");if(!n)throw new F('Graph.dropDirectedEdge: could not find a "'.concat(t,'" -> "').concat(e,'" edge in the graph.'));return Mt(this,n),this},i.dropUndirectedEdge=function(t,e){if(arguments.length<2)throw new I("Graph.dropUndirectedEdge: it does not make sense to drop a directed edge by key. What if the edge with this key is undirected? Use #.dropEdge for this purpose instead.");if(this.multi)throw new I("Graph.dropUndirectedEdge: cannot use a {source,target} combo when dropping an edge in a MultiGraph since we cannot infer the one you want to delete as there could be multiple ones.");var n=d(this,t,e,"undirected");if(!n)throw new F('Graph.dropUndirectedEdge: could not find a "'.concat(t,'" -> "').concat(e,'" edge in the graph.'));return Mt(this,n),this},i.clear=function(){this._edges.clear(),this._nodes.clear(),this._resetInstanceCounters(),this.emit("cleared")},i.clearEdges=function(){for(var t,e=this._nodes.values();!0!==(t=e.next()).done;)t.value.clear();this._edges.clear(),this._resetInstanceCounters(),this.emit("edgesCleared")},i.getAttribute=function(t){return this._attributes[t]},i.getAttributes=function(){return this._attributes},i.hasAttribute=function(t){return this._attributes.hasOwnProperty(t)},i.setAttribute=function(t,e){return this._attributes[t]=e,this.emit("attributesUpdated",{type:"set",attributes:this._attributes,name:t}),this},i.updateAttribute=function(t,e){if("function"!=typeof e)throw new B("Graph.updateAttribute: updater should be a function.");var n=this._attributes[t];return this._attributes[t]=e(n),this.emit("attributesUpdated",{type:"set",attributes:this._attributes,name:t}),this},i.removeAttribute=function(t){return delete this._attributes[t],this.emit("attributesUpdated",{type:"remove",attributes:this._attributes,name:t}),this},i.replaceAttributes=function(t){if(!s(t))throw new B("Graph.replaceAttributes: provided attributes are not a plain object.");return this._attributes=t,this.emit("attributesUpdated",{type:"replace",attributes:this._attributes}),this},i.mergeAttributes=function(t){if(!s(t))throw new B("Graph.mergeAttributes: provided attributes are not a plain object.");return u(this._attributes,t),this.emit("attributesUpdated",{type:"merge",attributes:this._attributes,data:t}),this},i.updateAttributes=function(t){if("function"!=typeof t)throw new B("Graph.updateAttributes: provided updater is not a function.");return this._attributes=t(this._attributes),this.emit("attributesUpdated",{type:"update",attributes:this._attributes}),this},i.updateEachNodeAttributes=function(t,e){if("function"!=typeof t)throw new B("Graph.updateEachNodeAttributes: expecting an updater function.");if(e&&!l(e))throw new B("Graph.updateEachNodeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}");for(var n,r,i=this._nodes.values();!0!==(n=i.next()).done;)(r=n.value).attributes=t(r.key,r.attributes);this.emit("eachNodeAttributesUpdated",{hints:e||null})},i.updateEachEdgeAttributes=function(t,e){if("function"!=typeof t)throw new B("Graph.updateEachEdgeAttributes: expecting an updater function.");if(e&&!l(e))throw new B("Graph.updateEachEdgeAttributes: invalid hints. Expecting an object having the following shape: {attributes?: [string]}");for(var n,r,i,o,a=this._edges.values();!0!==(n=a.next()).done;)i=(r=n.value).source,o=r.target,r.attributes=t(r.key,r.attributes,i.key,o.key,i.attributes,o.attributes,r.undirected);this.emit("eachEdgeAttributesUpdated",{hints:e||null})},i.forEachAdjacencyEntry=function(t){if("function"!=typeof t)throw new B("Graph.forEachAdjacencyEntry: expecting a callback.");xt(!1,!1,!1,this,t)},i.forEachAdjacencyEntryWithOrphans=function(t){if("function"!=typeof t)throw new B("Graph.forEachAdjacencyEntryWithOrphans: expecting a callback.");xt(!1,!1,!0,this,t)},i.forEachAssymetricAdjacencyEntry=function(t){if("function"!=typeof t)throw new B("Graph.forEachAssymetricAdjacencyEntry: expecting a callback.");xt(!1,!0,!1,this,t)},i.forEachAssymetricAdjacencyEntryWithOrphans=function(t){if("function"!=typeof t)throw new B("Graph.forEachAssymetricAdjacencyEntryWithOrphans: expecting a callback.");xt(!1,!0,!0,this,t)},i.nodes=function(){return"function"==typeof Array.from?Array.from(this._nodes.keys()):K(this._nodes.keys(),this._nodes.size)},i.forEachNode=function(t){if("function"!=typeof t)throw new B("Graph.forEachNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)t((n=e.value).key,n.attributes)},i.findNode=function(t){if("function"!=typeof t)throw new B("Graph.findNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)if(t((n=e.value).key,n.attributes))return n.key},i.mapNodes=function(t){if("function"!=typeof t)throw new B("Graph.mapNode: expecting a callback.");for(var e,n,r=this._nodes.values(),i=new Array(this.order),o=0;!0!==(e=r.next()).done;)n=e.value,i[o++]=t(n.key,n.attributes);return i},i.someNode=function(t){if("function"!=typeof t)throw new B("Graph.someNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)if(t((n=e.value).key,n.attributes))return!0;return!1},i.everyNode=function(t){if("function"!=typeof t)throw new B("Graph.everyNode: expecting a callback.");for(var e,n,r=this._nodes.values();!0!==(e=r.next()).done;)if(!t((n=e.value).key,n.attributes))return!1;return!0},i.filterNodes=function(t){if("function"!=typeof t)throw new B("Graph.filterNodes: expecting a callback.");for(var e,n,r=this._nodes.values(),i=[];!0!==(e=r.next()).done;)t((n=e.value).key,n.attributes)&&i.push(n.key);return i},i.reduceNodes=function(t,e){if("function"!=typeof t)throw new B("Graph.reduceNodes: expecting a callback.");if(arguments.length<2)throw new B("Graph.reduceNodes: missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array.");for(var n,r,i=e,o=this._nodes.values();!0!==(n=o.next()).done;)i=t(i,(r=n.value).key,r.attributes);return i},i.nodeEntries=function(){var t=this._nodes.values();return new O((function(){var e=t.next();if(e.done)return e;var n=e.value;return{value:{node:n.key,attributes:n.attributes},done:!1}}))},i.export=function(){var t=this,e=new Array(this._nodes.size),n=0;this._nodes.forEach((function(t,r){e[n++]=function(t,e){var n={key:t};return h(e.attributes)||(n.attributes=u({},e.attributes)),n}(r,t)}));var r=new Array(this._edges.size);return n=0,this._edges.forEach((function(e,i){r[n++]=function(t,e,n){var r={key:e,source:n.source.key,target:n.target.key};return h(n.attributes)||(r.attributes=u({},n.attributes)),"mixed"===t&&n.undirected&&(r.undirected=!0),r}(t.type,i,e)})),{options:{type:this.type,multi:this.multi,allowSelfLoops:this.allowSelfLoops},attributes:this.getAttributes(),nodes:e,edges:r}},i.import=function(t){var e,n,i,o,a,c=this,u=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(t instanceof r)return t.forEachNode((function(t,e){u?c.mergeNode(t,e):c.addNode(t,e)})),t.forEachEdge((function(t,e,n,r,i,o,a){u?a?c.mergeUndirectedEdgeWithKey(t,n,r,e):c.mergeDirectedEdgeWithKey(t,n,r,e):a?c.addUndirectedEdgeWithKey(t,n,r,e):c.addDirectedEdgeWithKey(t,n,r,e)})),this;if(!s(t))throw new B("Graph.import: invalid argument. Expecting a serialized graph or, alternatively, a Graph instance.");if(t.attributes){if(!s(t.attributes))throw new B("Graph.import: invalid attributes. Expecting a plain object.");u?this.mergeAttributes(t.attributes):this.replaceAttributes(t.attributes)}if(t.nodes){if(i=t.nodes,!Array.isArray(i))throw new B("Graph.import: invalid nodes. Expecting an array.");for(e=0,n=i.length;e",c="",u=t.source.key,d=t.target.key;t.undirected&&u>d&&(o=u,u=d,d=o);var s="(".concat(u,")").concat(a,"(").concat(d,")");n.startsWith("geid_")?e.multi&&(void 0===i[s]?i[s]=0:i[s]++,c+="".concat(i[s],". ")):c+="[".concat(n,"]: "),r[c+=s]=t.attributes}));var o={};for(var a in this)this.hasOwnProperty(a)&&!Ut.has(a)&&"function"!=typeof this[a]&&"symbol"!==t(a)&&(o[a]=this[a]);return o.attributes=this._attributes,o.nodes=n,o.edges=r,p(o,"constructor",this.constructor),o},r}(y.exports.EventEmitter);"undefined"!=typeof Symbol&&(zt.prototype[Symbol.for("nodejs.util.inspect.custom")]=zt.prototype.inspect),[{name:function(t){return"".concat(t,"Edge")},generateKey:!0},{name:function(t){return"".concat(t,"DirectedEdge")},generateKey:!0,type:"directed"},{name:function(t){return"".concat(t,"UndirectedEdge")},generateKey:!0,type:"undirected"},{name:function(t){return"".concat(t,"EdgeWithKey")}},{name:function(t){return"".concat(t,"DirectedEdgeWithKey")},type:"directed"},{name:function(t){return"".concat(t,"UndirectedEdgeWithKey")},type:"undirected"}].forEach((function(t){["add","merge","update"].forEach((function(e){var n=t.name(e),r="add"===e?jt:Ct;t.generateKey?zt.prototype[n]=function(i,o,a){return r(this,n,!0,"undirected"===(t.type||this.type),null,i,o,a,"update"===e)}:zt.prototype[n]=function(i,o,a,c){return r(this,n,!1,"undirected"===(t.type||this.type),i,o,a,c,"update"===e)}}))})),function(t){Q.forEach((function(e){var n=e.name,r=e.attacher;r(t,n("Node"),0),r(t,n("Source"),1),r(t,n("Target"),2),r(t,n("Opposite"),3)}))}(zt),function(t){X.forEach((function(e){var n=e.name,r=e.attacher;r(t,n("Edge"),"mixed"),r(t,n("DirectedEdge"),"directed"),r(t,n("UndirectedEdge"),"undirected")}))}(zt),function(t){et.forEach((function(e){!function(t,e){var n=e.name,r=e.type,i=e.direction;t.prototype[n]=function(t,e){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return[];if(!arguments.length)return ut(this,r);if(1===arguments.length){t=""+t;var o=this._nodes.get(t);if(void 0===o)throw new F("Graph.".concat(n,': could not find the "').concat(t,'" node in the graph.'));return pt(this.multi,"mixed"===r?this.type:r,i,o)}if(2===arguments.length){t=""+t,e=""+e;var a=this._nodes.get(t);if(!a)throw new F("Graph.".concat(n,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F("Graph.".concat(n,':  could not find the "').concat(e,'" target node in the graph.'));return gt(r,this.multi,i,a,e)}throw new B("Graph.".concat(n,": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length,")."))}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o="forEach"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[o]=function(t,e,n){if("mixed"===r||"mixed"===this.type||r===this.type){if(1===arguments.length)return dt(!1,this,r,n=t);if(2===arguments.length){t=""+t,n=e;var a=this._nodes.get(t);if(void 0===a)throw new F("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return ht(!1,this.multi,"mixed"===r?this.type:r,i,a,n)}if(3===arguments.length){t=""+t,e=""+e;var c=this._nodes.get(t);if(!c)throw new F("Graph.".concat(o,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F("Graph.".concat(o,':  could not find the "').concat(e,'" target node in the graph.'));return lt(!1,r,this.multi,i,c,e,n)}throw new B("Graph.".concat(o,": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length,")."))}};var a="map"+n[0].toUpperCase()+n.slice(1);t.prototype[a]=function(){var t,e=Array.prototype.slice.call(arguments),n=e.pop();if(0===e.length){var i=0;"directed"!==r&&(i+=this.undirectedSize),"undirected"!==r&&(i+=this.directedSize),t=new Array(i);var a=0;e.push((function(e,r,i,o,c,u,d){t[a++]=n(e,r,i,o,c,u,d)}))}else t=[],e.push((function(e,r,i,o,a,c,u){t.push(n(e,r,i,o,a,c,u))}));return this[o].apply(this,e),t};var c="filter"+n[0].toUpperCase()+n.slice(1);t.prototype[c]=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=[];return t.push((function(t,r,i,o,a,c,u){e(t,r,i,o,a,c,u)&&n.push(t)})),this[o].apply(this,t),n};var u="reduce"+n[0].toUpperCase()+n.slice(1);t.prototype[u]=function(){var t,e,n=Array.prototype.slice.call(arguments);if(n.length<2||n.length>4)throw new B("Graph.".concat(u,": invalid number of arguments (expecting 2, 3 or 4 and got ").concat(n.length,")."));if("function"==typeof n[n.length-1]&&"function"!=typeof n[n.length-2])throw new B("Graph.".concat(u,": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));2===n.length?(t=n[0],e=n[1],n=[]):3===n.length?(t=n[1],e=n[2],n=[n[0]]):4===n.length&&(t=n[2],e=n[3],n=[n[0],n[1]]);var r=e;return n.push((function(e,n,i,o,a,c,u){r=t(r,e,n,i,o,a,c,u)})),this[o].apply(this,n),r}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o="find"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[o]=function(t,e,n){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return!1;if(1===arguments.length)return dt(!0,this,r,n=t);if(2===arguments.length){t=""+t,n=e;var a=this._nodes.get(t);if(void 0===a)throw new F("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return ht(!0,this.multi,"mixed"===r?this.type:r,i,a,n)}if(3===arguments.length){t=""+t,e=""+e;var c=this._nodes.get(t);if(!c)throw new F("Graph.".concat(o,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F("Graph.".concat(o,':  could not find the "').concat(e,'" target node in the graph.'));return lt(!0,r,this.multi,i,c,e,n)}throw new B("Graph.".concat(o,": too many arguments (expecting 1, 2 or 3 and got ").concat(arguments.length,")."))};var a="some"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[a]=function(){var t=Array.prototype.slice.call(arguments),e=t.pop();return t.push((function(t,n,r,i,o,a,c){return e(t,n,r,i,o,a,c)})),!!this[o].apply(this,t)};var c="every"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[c]=function(){var t=Array.prototype.slice.call(arguments),e=t.pop();return t.push((function(t,n,r,i,o,a,c){return!e(t,n,r,i,o,a,c)})),!this[o].apply(this,t)}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o=n.slice(0,-1)+"Entries";t.prototype[o]=function(t,e){if("mixed"!==r&&"mixed"!==this.type&&r!==this.type)return O.empty();if(!arguments.length)return st(this,r);if(1===arguments.length){t=""+t;var n=this._nodes.get(t);if(!n)throw new F("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));return ft(r,i,n)}if(2===arguments.length){t=""+t,e=""+e;var a=this._nodes.get(t);if(!a)throw new F("Graph.".concat(o,':  could not find the "').concat(t,'" source node in the graph.'));if(!this._nodes.has(e))throw new F("Graph.".concat(o,':  could not find the "').concat(e,'" target node in the graph.'));return yt(r,i,a,e)}throw new B("Graph.".concat(o,": too many arguments (expecting 0, 1 or 2 and got ").concat(arguments.length,")."))}}(t,e)}))}(zt),function(t){wt.forEach((function(e){_t(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o="forEach"+n[0].toUpperCase()+n.slice(1,-1);t.prototype[o]=function(t,e){if("mixed"===r||"mixed"===this.type||r===this.type){t=""+t;var n=this._nodes.get(t);if(void 0===n)throw new F("Graph.".concat(o,': could not find the "').concat(t,'" node in the graph.'));mt(!1,"mixed"===r?this.type:r,i,n,e)}};var a="map"+n[0].toUpperCase()+n.slice(1);t.prototype[a]=function(t,e){var n=[];return this[o](t,(function(t,r){n.push(e(t,r))})),n};var c="filter"+n[0].toUpperCase()+n.slice(1);t.prototype[c]=function(t,e){var n=[];return this[o](t,(function(t,r){e(t,r)&&n.push(t)})),n};var u="reduce"+n[0].toUpperCase()+n.slice(1);t.prototype[u]=function(t,e,n){if(arguments.length<3)throw new B("Graph.".concat(u,": missing initial value. You must provide it because the callback takes more than one argument and we cannot infer the initial value from the first iteration, as you could with a simple array."));var r=n;return this[o](t,(function(t,n){r=e(r,t,n)})),r}}(t,e),function(t,e){var n=e.name,r=e.type,i=e.direction,o=n[0].toUpperCase()+n.slice(1,-1),a="find"+o;t.prototype[a]=function(t,e){if("mixed"===r||"mixed"===this.type||r===this.type){t=""+t;var n=this._nodes.get(t);if(void 0===n)throw new F("Graph.".concat(a,': could not find the "').concat(t,'" node in the graph.'));return mt(!0,"mixed"===r?this.type:r,i,n,e)}};var c="some"+o;t.prototype[c]=function(t,e){return!!this[a](t,e)};var u="every"+o;t.prototype[u]=function(t,e){return!this[a](t,(function(t,n){return!e(t,n)}))}}(t,e),Gt(t,e)}))}(zt);var Wt=function(t){function n(e){var n=u({type:"directed"},e);if("multi"in n&&!1!==n.multi)throw new B("DirectedGraph.from: inconsistent indication that the graph should be multi in given options!");if("directed"!==n.type)throw new B('DirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(zt),Pt=function(t){function n(e){var n=u({type:"undirected"},e);if("multi"in n&&!1!==n.multi)throw new B("UndirectedGraph.from: inconsistent indication that the graph should be multi in given options!");if("undirected"!==n.type)throw new B('UndirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(zt),Rt=function(t){function n(e){var n=u({multi:!0},e);if("multi"in n&&!0!==n.multi)throw new B("MultiGraph.from: inconsistent indication that the graph should be simple in given options!");return t.call(this,n)||this}return e(n,t),n}(zt),Kt=function(t){function n(e){var n=u({type:"directed",multi:!0},e);if("multi"in n&&!0!==n.multi)throw new B("MultiDirectedGraph.from: inconsistent indication that the graph should be simple in given options!");if("directed"!==n.type)throw new B('MultiDirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(zt),Tt=function(t){function n(e){var n=u({type:"undirected",multi:!0},e);if("multi"in n&&!0!==n.multi)throw new B("MultiUndirectedGraph.from: inconsistent indication that the graph should be simple in given options!");if("undirected"!==n.type)throw new B('MultiUndirectedGraph.from: inconsistent "'+n.type+'" type in given options!');return t.call(this,n)||this}return e(n,t),n}(zt);function Bt(t){t.from=function(e,n){var r=u({},e.options,n),i=new t(r);return i.import(e),i}}return Bt(zt),Bt(Wt),Bt(Pt),Bt(Rt),Bt(Kt),Bt(Tt),zt.Graph=zt,zt.DirectedGraph=Wt,zt.UndirectedGraph=Pt,zt.MultiGraph=Rt,zt.MultiDirectedGraph=Kt,zt.MultiUndirectedGraph=Tt,zt.InvalidArgumentsGraphError=B,zt.NotFoundGraphError=F,zt.UsageGraphError=I,zt}));
+//# sourceMappingURL=graphology.umd.min.js.map
diff --git a/static/htmx.min.js b/static/lib/htmx.min.js
similarity index 100%
rename from static/htmx.min.js
rename to static/lib/htmx.min.js
diff --git a/static/lib/sigma.min.js b/static/lib/sigma.min.js
new file mode 100644
index 0000000..3aadbd1
--- /dev/null
+++ b/static/lib/sigma.min.js
@@ -0,0 +1 @@
+var Sigma;(()=>{var t={796:t=>{t.exports=function(t,e){var r=e.length;if(0!==r){var i=t.length;t.length+=r;for(var n=0;n{"use strict";var e,r="object"==typeof Reflect?Reflect:null,i=r&&"function"==typeof r.apply?r.apply:function(t,e,r){return Function.prototype.apply.call(t,e,r)};e=r&&"function"==typeof r.ownKeys?r.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var n=Number.isNaN||function(t){return t!=t};function o(){o.init.call(this)}t.exports=o,t.exports.once=function(t,e){return new Promise((function(r,i){function n(r){t.removeListener(e,o),i(r)}function o(){"function"==typeof t.removeListener&&t.removeListener("error",n),r([].slice.call(arguments))}g(t,e,o,{once:!0}),"error"!==e&&function(t,e,r){"function"==typeof t.on&&g(t,"error",e,{once:!0})}(t,n)}))},o.EventEmitter=o,o.prototype._events=void 0,o.prototype._eventsCount=0,o.prototype._maxListeners=void 0;var a=10;function s(t){if("function"!=typeof t)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof t)}function h(t){return void 0===t._maxListeners?o.defaultMaxListeners:t._maxListeners}function l(t,e,r,i){var n,o,a,l;if(s(r),void 0===(o=t._events)?(o=t._events=Object.create(null),t._eventsCount=0):(void 0!==o.newListener&&(t.emit("newListener",e,r.listener?r.listener:r),o=t._events),a=o[e]),void 0===a)a=o[e]=r,++t._eventsCount;else if("function"==typeof a?a=o[e]=i?[r,a]:[a,r]:i?a.unshift(r):a.push(r),(n=h(t))>0&&a.length>n&&!a.warned){a.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+a.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=t,c.type=e,c.count=a.length,l=c,console&&console.warn&&console.warn(l)}return t}function c(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function u(t,e,r){var i={fired:!1,wrapFn:void 0,target:t,type:e,listener:r},n=c.bind(i);return n.listener=r,i.wrapFn=n,n}function d(t,e,r){var i=t._events;if(void 0===i)return[];var n=i[e];return void 0===n?[]:"function"==typeof n?r?[n.listener||n]:[n]:r?function(t){for(var e=new Array(t.length),r=0;r0&&(a=e[0]),a instanceof Error)throw a;var s=new Error("Unhandled error."+(a?" ("+a.message+")":""));throw s.context=a,s}var h=o[t];if(void 0===h)return!1;if("function"==typeof h)i(h,this,e);else{var l=h.length,c=p(h,l);for(r=0;r=0;o--)if(r[o]===e||r[o].listener===e){a=r[o].listener,n=o;break}if(n<0)return this;0===n?r.shift():function(t,e){for(;e+1=0;i--)this.removeListener(t,e[i]);return this},o.prototype.listeners=function(t){return d(this,t,!0)},o.prototype.rawListeners=function(t){return d(this,t,!1)},o.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):f.call(t,e)},o.prototype.listenerCount=f,o.prototype.eventNames=function(){return this._eventsCount>0?e(this._events):[]}},186:t=>{t.exports=function(t){return null!==t&&"object"==typeof t&&"function"==typeof t.addUndirectedEdgeWithKey&&"function"==typeof t.dropNode&&"boolean"==typeof t.multi}},973:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i="precision mediump float;\n\nvarying vec4 v_color;\n\nvoid main(void) {\n  gl_FragColor = v_color;\n}\n"},912:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i="attribute vec2 a_position;\nattribute vec2 a_normal;\nattribute float a_radius;\nattribute vec4 a_color;\nattribute vec3 a_barycentric;\n\nuniform mat3 u_matrix;\nuniform float u_sqrtZoomRatio;\nuniform float u_correctionRatio;\n\nvarying vec4 v_color;\n\nconst float minThickness = 1.7;\nconst float bias = 255.0 / 254.0;\nconst float arrowHeadWidthLengthRatio = 0.66;\nconst float arrowHeadLengthThicknessRatio = 2.5;\n\nvoid main() {\n  float normalLength = length(a_normal);\n  vec2 unitNormal = a_normal / normalLength;\n\n  // These first computations are taken from edge.vert.glsl and\n  // edge.clamped.vert.glsl. Please read it to get better comments on what's\n  // happening:\n  float pixelsThickness = max(normalLength, minThickness * u_sqrtZoomRatio);\n  float webGLThickness = pixelsThickness * u_correctionRatio;\n  float adaptedWebGLThickness = webGLThickness * u_sqrtZoomRatio;\n  float adaptedWebGLNodeRadius = a_radius * 2.0 * u_correctionRatio * u_sqrtZoomRatio;\n  float adaptedWebGLArrowHeadLength = adaptedWebGLThickness * 2.0 * arrowHeadLengthThicknessRatio;\n  float adaptedWebGLArrowHeadHalfWidth = adaptedWebGLArrowHeadLength * arrowHeadWidthLengthRatio / 2.0;\n\n  float da = a_barycentric.x;\n  float db = a_barycentric.y;\n  float dc = a_barycentric.z;\n\n  vec2 delta = vec2(\n      da * (adaptedWebGLNodeRadius * unitNormal.y)\n    + db * ((adaptedWebGLNodeRadius + adaptedWebGLArrowHeadLength) * unitNormal.y + adaptedWebGLArrowHeadHalfWidth * unitNormal.x)\n    + dc * ((adaptedWebGLNodeRadius + adaptedWebGLArrowHeadLength) * unitNormal.y - adaptedWebGLArrowHeadHalfWidth * unitNormal.x),\n\n      da * (-adaptedWebGLNodeRadius * unitNormal.x)\n    + db * (-(adaptedWebGLNodeRadius + adaptedWebGLArrowHeadLength) * unitNormal.x + adaptedWebGLArrowHeadHalfWidth * unitNormal.y)\n    + dc * (-(adaptedWebGLNodeRadius + adaptedWebGLArrowHeadLength) * unitNormal.x - adaptedWebGLArrowHeadHalfWidth * unitNormal.y)\n  );\n\n  vec2 position = (u_matrix * vec3(a_position + delta, 1)).xy;\n\n  gl_Position = vec4(position, 0, 1);\n\n  // Extract the color:\n  v_color = a_color;\n  v_color.a *= bias;\n}\n"},620:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i="attribute vec4 a_color;\nattribute vec2 a_normal;\nattribute vec2 a_position;\nattribute float a_radius;\n\nuniform mat3 u_matrix;\nuniform float u_sqrtZoomRatio;\nuniform float u_correctionRatio;\n\nvarying vec4 v_color;\nvarying vec2 v_normal;\nvarying float v_thickness;\n\nconst float minThickness = 1.7;\nconst float bias = 255.0 / 254.0;\nconst float arrowHeadLengthThicknessRatio = 2.5;\n\nvoid main() {\n  float normalLength = length(a_normal);\n  vec2 unitNormal = a_normal / normalLength;\n\n  // These first computations are taken from edge.vert.glsl. Please read it to\n  // get better comments on what's happening:\n  float pixelsThickness = max(normalLength, minThickness * u_sqrtZoomRatio);\n  float webGLThickness = pixelsThickness * u_correctionRatio;\n  float adaptedWebGLThickness = webGLThickness * u_sqrtZoomRatio;\n\n  // Here, we move the point to leave space for the arrow head:\n  float direction = sign(a_radius);\n  float adaptedWebGLNodeRadius = direction * a_radius * 2.0 * u_correctionRatio * u_sqrtZoomRatio;\n  float adaptedWebGLArrowHeadLength = adaptedWebGLThickness * 2.0 * arrowHeadLengthThicknessRatio;\n\n  vec2 compensationVector = vec2(-direction * unitNormal.y, direction * unitNormal.x) * (adaptedWebGLNodeRadius + adaptedWebGLArrowHeadLength);\n\n  // Here is the proper position of the vertex\n  gl_Position = vec4((u_matrix * vec3(a_position + unitNormal * adaptedWebGLThickness + compensationVector, 1)).xy, 0, 1);\n\n  v_thickness = webGLThickness / u_sqrtZoomRatio;\n\n  v_normal = unitNormal;\n  v_color = a_color;\n  v_color.a *= bias;\n}\n"},498:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i="precision mediump float;\n\nvarying vec4 v_color;\nvarying vec2 v_normal;\nvarying float v_thickness;\n\nconst float feather = 0.001;\nconst vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0);\n\nvoid main(void) {\n  float dist = length(v_normal) * v_thickness;\n\n  float t = smoothstep(\n    v_thickness - feather,\n    v_thickness,\n    dist\n  );\n\n  gl_FragColor = mix(v_color, transparent, t);\n}\n"},223:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i='attribute vec4 a_color;\nattribute vec2 a_normal;\nattribute vec2 a_position;\n\nuniform mat3 u_matrix;\nuniform float u_sqrtZoomRatio;\nuniform float u_correctionRatio;\n\nvarying vec4 v_color;\nvarying vec2 v_normal;\nvarying float v_thickness;\n\nconst float minThickness = 1.7;\nconst float bias = 255.0 / 254.0;\n\nvoid main() {\n  float normalLength = length(a_normal);\n  vec2 unitNormal = a_normal / normalLength;\n\n  // We require edges to be at least `minThickness` pixels thick *on screen*\n  // (so we need to compensate the SQRT zoom ratio):\n  float pixelsThickness = max(normalLength, minThickness * u_sqrtZoomRatio);\n\n  // Then, we need to retrieve the normalized thickness of the edge in the WebGL\n  // referential (in a ([0, 1], [0, 1]) space), using our "magic" correction\n  // ratio:\n  float webGLThickness = pixelsThickness * u_correctionRatio;\n\n  // Finally, we adapt the edge thickness to the "SQRT rule" in sigma (so that\n  // items are not too big when zoomed in, and not too small when zoomed out).\n  // The exact computation should be `adapted = value * zoom / sqrt(zoom)`, but\n  // it\'s simpler like this:\n  float adaptedWebGLThickness = webGLThickness * u_sqrtZoomRatio;\n\n  // Here is the proper position of the vertex\n  gl_Position = vec4((u_matrix * vec3(a_position + unitNormal * adaptedWebGLThickness, 1)).xy, 0, 1);\n\n  // For the fragment shader though, we need a thickness that takes the "magic"\n  // correction ratio into account (as in webGLThickness), but so that the\n  // antialiasing effect does not depend on the zoom level. So here\'s yet\n  // another thickness version:\n  v_thickness = webGLThickness / u_sqrtZoomRatio;\n\n  v_normal = unitNormal;\n  v_color = a_color;\n  v_color.a *= bias;\n}\n'},262:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i="precision mediump float;\n\nvarying vec4 v_color;\nvarying float v_border;\n\nconst float radius = 0.5;\nconst vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0);\n\nvoid main(void) {\n  vec2 m = gl_PointCoord - vec2(0.5, 0.5);\n  float dist = radius - length(m);\n\n  float t = 0.0;\n  if (dist > v_border)\n    t = 1.0;\n  else if (dist > 0.0)\n    t = dist / v_border;\n\n  gl_FragColor = mix(transparent, v_color, t);\n}\n"},106:(t,e,r)=>{"use strict";r.r(e),r.d(e,{default:()=>i});const i="attribute vec2 a_position;\nattribute float a_size;\nattribute vec4 a_color;\n\nuniform float u_ratio;\nuniform float u_scale;\nuniform mat3 u_matrix;\n\nvarying vec4 v_color;\nvarying float v_border;\n\nconst float bias = 255.0 / 254.0;\n\nvoid main() {\n  gl_Position = vec4(\n    (u_matrix * vec3(a_position, 1)).xy,\n    0,\n    1\n  );\n\n  // Multiply the point size twice:\n  //  - x SCALING_RATIO to correct the canvas scaling\n  //  - x 2 to correct the formulae\n  gl_PointSize = a_size * u_ratio * u_scale * 2.0;\n\n  v_border = (1.0 / u_ratio) * (0.5 / a_size);\n\n  // Extract the color:\n  v_color = a_color;\n  v_color.a *= bias;\n}\n"},764:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),o=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var a=r(751),s=o(r(358)),h=r(928),l=r(699),c=1.5,u=function(t){function e(){var e=t.call(this)||this;return e.x=.5,e.y=.5,e.angle=0,e.ratio=1,e.minRatio=null,e.maxRatio=null,e.nextFrame=null,e.previousState=null,e.enabled=!0,e.previousState=e.getState(),e}return n(e,t),e.from=function(t){return(new e).setState(t)},e.prototype.enable=function(){return this.enabled=!0,this},e.prototype.disable=function(){return this.enabled=!1,this},e.prototype.getState=function(){return{x:this.x,y:this.y,angle:this.angle,ratio:this.ratio}},e.prototype.hasState=function(t){return this.x===t.x&&this.y===t.y&&this.ratio===t.ratio&&this.angle===t.angle},e.prototype.getPreviousState=function(){var t=this.previousState;return t?{x:t.x,y:t.y,angle:t.angle,ratio:t.ratio}:null},e.prototype.getBoundedRatio=function(t){var e=t;return"number"==typeof this.minRatio&&(e=Math.max(e,this.minRatio)),"number"==typeof this.maxRatio&&(e=Math.min(e,this.maxRatio)),e},e.prototype.validateState=function(t){var e={};return"number"==typeof t.x&&(e.x=t.x),"number"==typeof t.y&&(e.y=t.y),"number"==typeof t.angle&&(e.angle=t.angle),"number"==typeof t.ratio&&(e.ratio=this.getBoundedRatio(t.ratio)),e},e.prototype.isAnimated=function(){return!!this.nextFrame},e.prototype.setState=function(t){if(!this.enabled)return this;this.previousState=this.getState();var e=this.validateState(t);return"number"==typeof e.x&&(this.x=e.x),"number"==typeof e.y&&(this.y=e.y),"number"==typeof e.angle&&(this.angle=e.angle),"number"==typeof e.ratio&&(this.ratio=e.ratio),this.hasState(this.previousState)||this.emit("updated",this.getState()),this},e.prototype.updateState=function(t){return this.setState(t(this.getState())),this},e.prototype.animate=function(t,e,r){var i=this;if(this.enabled){var n=Object.assign({},a.ANIMATE_DEFAULTS,e),o=this.validateState(t),l="function"==typeof n.easing?n.easing:s.default[n.easing],c=Date.now(),u=this.getState(),d=function(){var t=(Date.now()-c)/n.duration;if(t>=1)return i.nextFrame=null,i.setState(o),void(i.animationCallback&&(i.animationCallback.call(null),i.animationCallback=void 0));var e=l(t),r={};"number"==typeof o.x&&(r.x=u.x+(o.x-u.x)*e),"number"==typeof o.y&&(r.y=u.y+(o.y-u.y)*e),"number"==typeof o.angle&&(r.angle=u.angle+(o.angle-u.angle)*e),"number"==typeof o.ratio&&(r.ratio=u.ratio+(o.ratio-u.ratio)*e),i.setState(r),i.nextFrame=(0,h.requestFrame)(d)};this.nextFrame?((0,h.cancelFrame)(this.nextFrame),this.animationCallback&&this.animationCallback.call(null),this.nextFrame=(0,h.requestFrame)(d)):d(),this.animationCallback=r}},e.prototype.animatedZoom=function(t){if(t){if("number"==typeof t)return this.animate({ratio:this.ratio/t});this.animate({ratio:this.ratio/(t.factor||c)},t)}else this.animate({ratio:this.ratio/c})},e.prototype.animatedUnzoom=function(t){if(t){if("number"==typeof t)return this.animate({ratio:this.ratio*t});this.animate({ratio:this.ratio*(t.factor||c)},t)}else this.animate({ratio:this.ratio*c})},e.prototype.animatedReset=function(t){this.animate({x:.5,y:.5,ratio:1,angle:0},t)},e.prototype.copy=function(){return e.from(this.getState())},e}(l.TypedEventEmitter);e.default=u},291:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),o=this&&this.__assign||function(){return o=Object.assign||function(t){for(var e,r=1,i=arguments.length;r0?1/1.7:1.7,o=this.renderer.getCamera(),a=o.getBoundedRatio(o.getState().ratio*n),s=r>0?1:-1,l=Date.now();this.currentWheelDirection===s&&this.lastWheelTriggerTime&&l-this.lastWheelTriggerTime<50||(o.animate(this.renderer.getViewportZoomedState((0,h.getPosition)(t,this.container),a),{easing:"quadraticOut",duration:250},(function(){e.currentWheelDirection=0})),this.currentWheelDirection=s,this.lastWheelTriggerTime=l)}}}},e.prototype.handleOut=function(){},e}(h.default);e.default=l},508:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),o=this&&this.__createBinding||(Object.create?function(t,e,r,i){void 0===i&&(i=r),Object.defineProperty(t,i,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,i){void 0===i&&(i=r),t[i]=e[r]}),a=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),s=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)"default"!==r&&Object.prototype.hasOwnProperty.call(t,r)&&o(e,t,r);return a(e,t),e},h=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var i,n,o=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(i=o.next()).done;)a.push(i.value)}catch(t){n={error:t}}finally{try{i&&!i.done&&(r=o.return)&&r.call(o)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0});var l=s(r(291)),c=function(t){function e(e,r){var i=t.call(this,e,r)||this;return i.enabled=!0,i.isMoving=!1,i.hasMoved=!1,i.touchMode=0,i.startTouchesPositions=[],i.handleStart=i.handleStart.bind(i),i.handleLeave=i.handleLeave.bind(i),i.handleMove=i.handleMove.bind(i),e.addEventListener("touchstart",i.handleStart,!1),e.addEventListener("touchend",i.handleLeave,!1),e.addEventListener("touchcancel",i.handleLeave,!1),e.addEventListener("touchmove",i.handleMove,!1),i}return n(e,t),e.prototype.kill=function(){var t=this.container;t.removeEventListener("touchstart",this.handleStart),t.removeEventListener("touchend",this.handleLeave),t.removeEventListener("touchcancel",this.handleLeave),t.removeEventListener("touchmove",this.handleMove)},e.prototype.getDimensions=function(){return{width:this.container.offsetWidth,height:this.container.offsetHeight}},e.prototype.dispatchRelatedMouseEvent=function(t,e,r,i){var n=r||e.touches[0],o=new MouseEvent(t,{clientX:n.clientX,clientY:n.clientY,altKey:e.altKey,ctrlKey:e.ctrlKey});o.isFakeSigmaMouseEvent=!0,(i||this.container).dispatchEvent(o)},e.prototype.handleStart=function(t){var e=this;if(this.enabled){t.preventDefault(),1===t.touches.length&&this.dispatchRelatedMouseEvent("mousedown",t);var r=(0,l.getTouchesArray)(t.touches);if(this.touchMode=r.length,this.startCameraState=this.renderer.getCamera().getState(),this.startTouchesPositions=r.map((function(t){return(0,l.getPosition)(t,e.container)})),this.lastTouches=r,this.lastTouchesPositions=this.startTouchesPositions,2===this.touchMode){var i=h(this.startTouchesPositions,2),n=i[0],o=n.x,a=n.y,s=i[1],c=s.x,u=s.y;this.startTouchesAngle=Math.atan2(u-a,c-o),this.startTouchesDistance=Math.sqrt(Math.pow(c-o,2)+Math.pow(u-a,2))}this.emit("touchdown",(0,l.getTouchCoords)(t,this.container))}},e.prototype.handleLeave=function(t){if(this.enabled){switch(t.preventDefault(),0===t.touches.length&&this.lastTouches&&this.lastTouches.length&&(this.dispatchRelatedMouseEvent("mouseup",t,this.lastTouches[0],document),this.hasMoved||this.dispatchRelatedMouseEvent("click",t,this.lastTouches[0])),this.movingTimeout&&(this.isMoving=!1,clearTimeout(this.movingTimeout)),this.touchMode){case 2:if(1===t.touches.length){this.handleStart(t),t.preventDefault();break}case 1:if(this.isMoving){var e=this.renderer.getCamera(),r=e.getState(),i=e.getPreviousState()||{x:0,y:0};e.animate({x:r.x+3*(r.x-i.x),y:r.y+3*(r.y-i.y)},{duration:200,easing:"quadraticOut"})}this.hasMoved=!1,this.isMoving=!1,this.touchMode=0}this.emit("touchup",(0,l.getTouchCoords)(t,this.container))}},e.prototype.handleMove=function(t){var e,r=this;if(this.enabled){t.preventDefault(),1===t.touches.length&&this.dispatchRelatedMouseEvent("mousemove",t);var i=(0,l.getTouchesArray)(t.touches),n=i.map((function(t){return(0,l.getPosition)(t,r.container)}));if(this.lastTouches=i,this.lastTouchesPositions=n,this.hasMoved||(this.hasMoved=n.some((function(t,e){var i=r.startTouchesPositions[e];return t.x!==i.x||t.y!==i.y}))),this.hasMoved){this.isMoving=!0,this.movingTimeout&&clearTimeout(this.movingTimeout),this.movingTimeout=window.setTimeout((function(){r.isMoving=!1}),200);var o=this.renderer.getCamera(),a=this.startCameraState;switch(this.touchMode){case 1:var s=this.renderer.viewportToFramedGraph((this.startTouchesPositions||[])[0]),c=s.x,u=s.y,d=this.renderer.viewportToFramedGraph(n[0]),f=d.x,p=d.y;o.setState({x:a.x+c-f,y:a.y+u-p});break;case 2:var g={},v=n[0],m=v.x,y=v.y,b=n[1],_=b.x,x=b.y,w=Math.atan2(x-y,_-m)-this.startTouchesAngle,E=Math.hypot(x-y,_-m)/this.startTouchesDistance,L=o.getBoundedRatio(a.ratio/E);g.ratio=L,g.angle=a.angle+w;var F=this.getDimensions(),C=this.renderer.viewportToFramedGraph((this.startTouchesPositions||[])[0],{cameraState:a}),A=Math.min(F.width,F.height),T=A/F.width,P=L/A;p=y-A/2/(A/F.height),f=(e=h([(f=m-A/2/T)*Math.cos(-g.angle)-p*Math.sin(-g.angle),p*Math.cos(-g.angle)+f*Math.sin(-g.angle)],2))[0],p=e[1],g.x=C.x-f*P,g.y=C.y+p*P,o.setState(g)}this.emit("touchmove",(0,l.getTouchCoords)(t,this.container))}}},e}(l.default);e.default=c},730:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.edgeLabelsToDisplayFromNodes=e.LabelGrid=void 0;var r=function(){function t(t,e){this.key=t,this.size=e}return t.compare=function(t,e){return t.size>e.size?-1:t.sizee.key?1:-1},t}(),i=function(){function t(){this.width=0,this.height=0,this.cellSize=0,this.columns=0,this.rows=0,this.cells={}}return t.prototype.resizeAndClear=function(t,e){this.width=t.width,this.height=t.height,this.cellSize=e,this.columns=Math.ceil(t.width/e),this.rows=Math.ceil(t.height/e),this.cells={}},t.prototype.getIndex=function(t){var e=Math.floor(t.x/this.cellSize);return Math.floor(t.y/this.cellSize)*this.columns+e},t.prototype.add=function(t,e,i){var n=new r(t,e),o=this.getIndex(i),a=this.cells[o];a||(a=[],this.cells[o]=a),a.push(n)},t.prototype.organize=function(){for(var t in this.cells)this.cells[t].sort(r.compare)},t.prototype.getLabelsToDisplay=function(t,e){var r=this.cellSize*this.cellSize,i=r/t/t*e/r,n=Math.ceil(i),o=[];for(var a in this.cells)for(var s=this.cells[a],h=0;hi&&en}function l(t,e,r,i,n,o,a,s){return tn&&eo}function c(t,e,r,i,n,o){var a=t=5)return r[f]=r[f]||[],void r[f].push(i);var p=4*f+4,g=4*f+8,v=4*f+12,m=4*f+16,y=h(l,c,u,e[p+0],e[p+1],e[p+2],e[p+3]),b=h(l,c,u,e[g+0],e[g+1],e[g+2],e[g+3]),_=h(l,c,u,e[v+0],e[v+1],e[v+2],e[v+3]),x=h(l,c,u,e[m+0],e[m+1],e[m+2],e[m+3]),w=[y,b,_,x].reduce((function(t,e){return e?t+1:t}),0);if(0===w&&0===d)return r[5460].push(i),void(!o&&r[5460].length>=5&&(o=!0,console.warn("sigma/quadtree.insertNode: At least 5 nodes are outside the global quadtree zone. You might have a problem with the normalization function or the custom bounding box.")));if(0===w)throw new Error("sigma/quadtree.insertNode: no collision (level: ".concat(d,", key: ").concat(i,", x: ").concat(n,", y: ").concat(a,", size: ").concat(s,")."));if(3===w)throw new Error("sigma/quadtree.insertNode: 3 impossible collisions (level: ".concat(d,", key: ").concat(i,", x: ").concat(n,", y: ").concat(a,", size: ").concat(s,")."));if(w>1)return r[f]=r[f]||[],void r[f].push(i);d++,y&&(f=p),b&&(f=g),_&&(f=v),x&&(f=m)}}(0,this.data,this.containers,t,e,r,i),this},t.prototype.resize=function(t){this.clear(),this.data[0]=t.x,this.data[1]=t.y,this.data[2]=t.width,this.data[3]=t.height,function(t,e){for(var r=[0,0];r.length;){var i=r.pop(),n=r.pop(),o=4*n+4,a=4*n+8,s=4*n+12,h=4*n+16,l=e[n+0],c=e[n+1],u=e[n+2]/2,d=e[n+3]/2;e[o+0]=l,e[o+1]=c,e[o+2]=u,e[o+3]=d,e[a+0]=l+u,e[a+1]=c,e[a+2]=u,e[a+3]=d,e[s+0]=l,e[s+1]=c+d,e[s+2]=u,e[s+3]=d,e[h+0]=l+u,e[h+1]=c+d,e[h+2]=u,e[h+3]=d,i<4&&(r.push(h,i+1),r.push(s,i+1),r.push(a,i+1),r.push(o,i+1))}}(0,this.data)},t.prototype.clear=function(){var t;return this.containers=((t={})[5460]=[],t),this},t.prototype.point=function(t,e){var r=this.containers[5460].slice(),i=0,o=0;do{this.containers[i]&&(0,n.default)(r,this.containers[i]),i=4*i+4*c(t,e,this.data[i+0],this.data[i+1],this.data[i+2],this.data[i+3]),o++}while(o<=5);return r},t.prototype.rectangle=function(t,e,r,i,o){var h=this.lastRectangle;return h&&t===h.x1&&r===h.x2&&e===h.y1&&i===h.y2&&o===h.height||(this.lastRectangle={x1:t,y1:e,x2:r,y2:i,height:o},a(this.lastRectangle)||(this.lastRectangle=s(this.lastRectangle)),this.cache=function(t,e,r,i,o,a,s){for(var h,c=[0,0],u=[];c.length;){var d=c.pop(),f=c.pop();if((h=r[f])&&(0,n.default)(u,h),!(d>=5)){var p=4*f+4,g=4*f+8,v=4*f+12,m=4*f+16,y=l(i,o,a,s,e[p+0],e[p+1],e[p+2],e[p+3]),b=l(i,o,a,s,e[g+0],e[g+1],e[g+2],e[g+3]),_=l(i,o,a,s,e[v+0],e[v+1],e[v+2],e[v+3]),x=l(i,o,a,s,e[m+0],e[m+1],e[m+2],e[m+3]);y&&c.push(p,d+1),b&&c.push(g,d+1),_&&c.push(v,d+1),x&&c.push(m,d+1)}}return u}(0,this.data,this.containers,t,e,Math.abs(t-r)||Math.abs(e-i),o),(0,n.default)(this.cache,this.containers[5460])),this.cache},t}();e.default=u},265:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),o=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var a=o(r(159)),s=o(r(764)),h=o(r(134)),l=o(r(269)),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.Camera=s.default,e.QuadTree=h.default,e.MouseCaptor=l.default,e.Sigma=a.default,e}(a.default);t.exports=c},942:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(t,e,r,i,n){var o=n.edgeLabelSize,a=n.edgeLabelFont,s=n.edgeLabelWeight,h=n.edgeLabelColor.attribute?e[n.edgeLabelColor.attribute]||n.edgeLabelColor.color||"#000":n.edgeLabelColor.color,l=e.label;if(l){t.fillStyle=h,t.font="".concat(s," ").concat(o,"px ").concat(a);var c,u,d=r.size,f=i.size,p=r.x,g=r.y,v=i.x,m=i.y,y=v-p,b=m-g,_=Math.sqrt(y*y+b*b);if(!(__){for(l+="…",w=t.measureText(l).width;w>_&&l.length>1;)l=l.slice(0,-2)+"…",w=t.measureText(l).width;if(l.length<4)return}x=y>0?b>0?Math.acos(y/_):Math.asin(b/_):b>0?Math.acos(y/_)+Math.PI:Math.asin(y/_)+Math.PI/2,t.save(),t.translate(c,u),t.rotate(x),t.fillText(l,-w/2,e.size/2+o),t.restore()}}}},61:function(t,e,r){"use strict";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var n=i(r(622));e.default=function(t,e,r){var i=r.labelSize,o=r.labelFont,a=r.labelWeight;if(t.font="".concat(a," ").concat(i,"px ").concat(o),t.fillStyle="#FFF",t.shadowOffsetX=0,t.shadowOffsetY=0,t.shadowBlur=8,t.shadowColor="#000","string"==typeof e.label){var s=t.measureText(e.label).width,h=Math.round(s+5),l=Math.round(i+4),c=Math.max(e.size,i/2)+2,u=Math.asin(l/2/c),d=Math.sqrt(Math.abs(Math.pow(c,2)-Math.pow(l/2,2)));t.beginPath(),t.moveTo(e.x+d,e.y+l/2),t.lineTo(e.x+c+h,e.y+l/2),t.lineTo(e.x+c+h,e.y-l/2),t.lineTo(e.x+d,e.y-l/2),t.arc(e.x,e.y,c,u,-u),t.closePath(),t.fill()}else t.beginPath(),t.arc(e.x,e.y,e.size+2,0,2*Math.PI),t.closePath(),t.fill();t.shadowOffsetX=0,t.shadowOffsetY=0,t.shadowBlur=0,(0,n.default)(t,e,r)}},622:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(t,e,r){if(e.label){var i=r.labelSize,n=r.labelFont,o=r.labelWeight,a=r.labelColor.attribute?e[r.labelColor.attribute]||r.labelColor.color||"#000":r.labelColor.color;t.fillStyle=a,t.font="".concat(o," ").concat(i,"px ").concat(n),t.fillText(e.label,e.x+e.size+3,e.y+i/3)}}},195:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.createEdgeCompoundProgram=e.AbstractEdgeProgram=void 0;var o=function(t){function e(e,r,i,n,o){return t.call(this,e,r,i,n,o)||this}return n(e,t),e}(r(171).AbstractProgram);e.AbstractEdgeProgram=o,e.createEdgeCompoundProgram=function(t){return function(){function e(e,r){this.programs=t.map((function(t){return new t(e,r)}))}return e.prototype.bufferData=function(){this.programs.forEach((function(t){return t.bufferData()}))},e.prototype.allocate=function(t){this.programs.forEach((function(e){return e.allocate(t)}))},e.prototype.bind=function(){},e.prototype.computeIndices=function(){this.programs.forEach((function(t){return t.computeIndices()}))},e.prototype.render=function(t){this.programs.forEach((function(e){e.bind(),e.bufferData(),e.render(t)}))},e.prototype.process=function(t,e,r,i,n){this.programs.forEach((function(o){return o.process(t,e,r,i,n)}))},e}()}},909:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.createNodeCompoundProgram=e.AbstractNodeProgram=void 0;var o=function(t){function e(e,r,i,n,o){var a=t.call(this,e,r,i,n,o)||this;a.positionLocation=e.getAttribLocation(a.program,"a_position"),a.sizeLocation=e.getAttribLocation(a.program,"a_size"),a.colorLocation=e.getAttribLocation(a.program,"a_color");var s=e.getUniformLocation(a.program,"u_matrix");if(null===s)throw new Error("AbstractNodeProgram: error while getting matrixLocation");a.matrixLocation=s;var h=e.getUniformLocation(a.program,"u_ratio");if(null===h)throw new Error("AbstractNodeProgram: error while getting ratioLocation");a.ratioLocation=h;var l=e.getUniformLocation(a.program,"u_scale");if(null===l)throw new Error("AbstractNodeProgram: error while getting scaleLocation");return a.scaleLocation=l,a}return n(e,t),e.prototype.bind=function(){var t=this.gl;t.enableVertexAttribArray(this.positionLocation),t.enableVertexAttribArray(this.sizeLocation),t.enableVertexAttribArray(this.colorLocation),t.vertexAttribPointer(this.positionLocation,2,t.FLOAT,!1,this.attributes*Float32Array.BYTES_PER_ELEMENT,0),t.vertexAttribPointer(this.sizeLocation,1,t.FLOAT,!1,this.attributes*Float32Array.BYTES_PER_ELEMENT,8),t.vertexAttribPointer(this.colorLocation,4,t.UNSIGNED_BYTE,!0,this.attributes*Float32Array.BYTES_PER_ELEMENT,12)},e}(r(171).AbstractProgram);e.AbstractNodeProgram=o,e.createNodeCompoundProgram=function(t){return function(){function e(e,r){this.programs=t.map((function(t){return new t(e,r)}))}return e.prototype.bufferData=function(){this.programs.forEach((function(t){return t.bufferData()}))},e.prototype.allocate=function(t){this.programs.forEach((function(e){return e.allocate(t)}))},e.prototype.bind=function(){},e.prototype.render=function(t){this.programs.forEach((function(e){e.bind(),e.bufferData(),e.render(t)}))},e.prototype.process=function(t,e,r){this.programs.forEach((function(i){return i.process(t,e,r)}))},e}()}},171:(t,e,r)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractProgram=void 0;var i=r(706),n=function(){function t(t,e,r,n,o){this.array=new Float32Array,this.points=n,this.attributes=o,this.gl=t,this.vertexShaderSource=e,this.fragmentShaderSource=r;var a=t.createBuffer();if(null===a)throw new Error("AbstractProgram: error while creating the buffer");this.buffer=a,t.bindBuffer(t.ARRAY_BUFFER,this.buffer),this.vertexShader=(0,i.loadVertexShader)(t,this.vertexShaderSource),this.fragmentShader=(0,i.loadFragmentShader)(t,this.fragmentShaderSource),this.program=(0,i.loadProgram)(t,[this.vertexShader,this.fragmentShader])}return t.prototype.bufferData=function(){var t=this.gl;t.bufferData(t.ARRAY_BUFFER,this.array,t.DYNAMIC_DRAW)},t.prototype.allocate=function(t){this.array=new Float32Array(this.points*this.attributes*t)},t.prototype.hasNothingToRender=function(){return 0===this.array.length},t}();e.AbstractProgram=n},569:function(t,e,r){"use strict";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var n=r(195),o=i(r(805)),a=i(r(483)),s=(0,n.createEdgeCompoundProgram)([a.default,o.default]);e.default=s},805:function(t,e,r){"use strict";var i,n=this&&this.__extends||(i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])},i(t,e)},function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function r(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),o=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var a=r(928),s=o(r(912)),h=o(r(973)),l=function(t){function e(e){var r=t.call(this,e,s.default,h.default,3,9)||this;r.positionLocation=e.getAttribLocation(r.program,"a_position"),r.colorLocation=e.getAttribLocation(r.program,"a_color"),r.normalLocation=e.getAttribLocation(r.program,"a_normal"),r.radiusLocation=e.getAttribLocation(r.program,"a_radius"),r.barycentricLocation=e.getAttribLocation(r.program,"a_barycentric");var i=e.getUniformLocation(r.program,"u_matrix");if(null===i)throw new Error("EdgeArrowHeadProgram: error while getting matrixLocation");r.matrixLocation=i;var n=e.getUniformLocation(r.program,"u_sqrtZoomRatio");if(null===n)throw new Error("EdgeArrowHeadProgram: error while getting sqrtZoomRatioLocation");r.sqrtZoomRatioLocation=n;var o=e.getUniformLocation(r.program,"u_correctionRatio");if(null===o)throw new Error("EdgeArrowHeadProgram: error while getting correctionRatioLocation");return r.correctionRatioLocation=o,r.bind(),r}return n(e,t),e.prototype.bind=function(){var t=this.gl;t.enableVertexAttribArray(this.positionLocation),t.enableVertexAttribArray(this.normalLocation),t.enableVertexAttribArray(this.radiusLocation),t.enableVertexAttribArray(this.colorLocation),t.enableVertexAttribArray(this.barycentricLocation),t.vertexAttribPointer(this.positionLocation,2,t.FLOAT,!1,9*Float32Array.BYTES_PER_ELEMENT,0),t.vertexAttribPointer(this.normalLocation,2,t.FLOAT,!1,9*Float32Array.BYTES_PER_ELEMENT,8),t.vertexAttribPointer(this.radiusLocation,1,t.FLOAT,!1,9*Float32Array.BYTES_PER_ELEMENT,16),t.vertexAttribPointer(this.colorLocation,4,t.UNSIGNED_BYTE,!0,9*Float32Array.BYTES_PER_ELEMENT,20),t.vertexAttribPointer(this.barycentricLocation,3,t.FLOAT,!1,9*Float32Array.BYTES_PER_ELEMENT,24)},e.prototype.computeIndices=function(){},e.prototype.process=function(t,e,r,i,n){if(i)for(var o=27*n,s=o+27;o{"use strict";function r(t,e,r){var i="VERTEX"===t?e.VERTEX_SHADER:e.FRAGMENT_SHADER,n=e.createShader(i);if(null===n)throw new Error("loadShader: error while creating the shader");if(e.shaderSource(n,r),e.compileShader(n),!e.getShaderParameter(n,e.COMPILE_STATUS)){var o=e.getShaderInfoLog(n);throw e.deleteShader(n),new Error("loadShader: error while compiling the shader:\n".concat(o,"\n").concat(r))}return n}Object.defineProperty(e,"__esModule",{value:!0}),e.loadProgram=e.loadFragmentShader=e.loadVertexShader=void 0,e.loadVertexShader=function(t,e){return r("VERTEX",t,e)},e.loadFragmentShader=function(t,e){return r("FRAGMENT",t,e)},e.loadProgram=function(t,e){var r,i,n=t.createProgram();if(null===n)throw new Error("loadProgram: error while creating the program.");for(r=0,i=e.length;r=t.length&&(t=void 0),{value:t&&t[i++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});var h=s(r(796)),l=s(r(764)),c=s(r(269)),u=s(r(134)),d=r(699),f=r(928),p=r(730),g=r(310),v=s(r(508)),m=r(700),y=r(628);function b(t,e,r){if(!r.hasOwnProperty("x")||!r.hasOwnProperty("y"))throw new Error('Sigma: could not find a valid position (x, y) for node "'.concat(e,'". All your nodes must have a number "x" and "y". Maybe your forgot to apply a layout or your "nodeReducer" is not returning the correct data?'));return r.color||(r.color=t.defaultNodeColor),r.label||""===r.label||(r.label=null),void 0!==r.label&&null!==r.label?r.label=""+r.label:r.label=null,r.size||(r.size=2),r.hasOwnProperty("hidden")||(r.hidden=!1),r.hasOwnProperty("highlighted")||(r.highlighted=!1),r.hasOwnProperty("forceLabel")||(r.forceLabel=!1),r.type&&""!==r.type||(r.type=t.defaultNodeType),r.zIndex||(r.zIndex=0),r}function _(t,e,r){return r.color||(r.color=t.defaultEdgeColor),r.label||(r.label=""),r.size||(r.size=.5),r.hasOwnProperty("hidden")||(r.hidden=!1),r.hasOwnProperty("forceLabel")||(r.forceLabel=!1),r.type&&""!==r.type||(r.type=t.defaultEdgeType),r.zIndex||(r.zIndex=0),r}var x=function(t){function e(e,r,i){void 0===i&&(i={});var n=t.call(this)||this;if(n.elements={},n.canvasContexts={},n.webGLContexts={},n.activeListeners={},n.quadtree=new u.default,n.labelGrid=new p.LabelGrid,n.nodeDataCache={},n.edgeDataCache={},n.nodesWithForcedLabels=[],n.edgesWithForcedLabels=[],n.nodeExtent={x:[0,1],y:[0,1]},n.matrix=(0,m.identity)(),n.invMatrix=(0,m.identity)(),n.correctionRatio=1,n.customBBox=null,n.normalizationFunction=(0,f.createNormalizationFunction)({x:[0,1],y:[0,1]}),n.cameraSizeRatio=1,n.width=0,n.height=0,n.pixelRatio=(0,f.getPixelRatio)(),n.displayedLabels=new Set,n.highlightedNodes=new Set,n.hoveredNode=null,n.hoveredEdge=null,n.renderFrame=null,n.renderHighlightedNodesFrame=null,n.needToProcess=!1,n.needToSoftProcess=!1,n.checkEdgesEventsFrame=null,n.nodePrograms={},n.nodeHoverPrograms={},n.edgePrograms={},n.settings=(0,g.resolveSettings)(i),(0,g.validateSettings)(n.settings),(0,f.validateGraph)(e),!(r instanceof HTMLElement))throw new Error("Sigma: container should be an html element.");for(var o in n.graph=e,n.container=r,n.createWebGLContext("edges",{preserveDrawingBuffer:!0}),n.createCanvasContext("edgeLabels"),n.createWebGLContext("nodes"),n.createCanvasContext("labels"),n.createCanvasContext("hovers"),n.createWebGLContext("hoverNodes"),n.createCanvasContext("mouse"),n.webGLContexts){var a=n.webGLContexts[o];a.blendFunc(a.ONE,a.ONE_MINUS_SRC_ALPHA),a.enable(a.BLEND)}for(var s in n.settings.nodeProgramClasses){var h=n.settings.nodeProgramClasses[s];n.nodePrograms[s]=new h(n.webGLContexts.nodes,n);var d=h;s in n.settings.nodeHoverProgramClasses&&(d=n.settings.nodeHoverProgramClasses[s]),n.nodeHoverPrograms[s]=new d(n.webGLContexts.hoverNodes,n)}for(var s in n.settings.edgeProgramClasses){var y=n.settings.edgeProgramClasses[s];n.edgePrograms[s]=new y(n.webGLContexts.edges,n)}return n.resize(),n.camera=new l.default,n.bindCameraHandlers(),n.mouseCaptor=new c.default(n.elements.mouse,n),n.touchCaptor=new v.default(n.elements.mouse,n),n.bindEventHandlers(),n.bindGraphHandlers(),n.handleSettingsUpdate(),n.process(),n.render(),n}return n(e,t),e.prototype.createCanvas=function(t){var e=(0,f.createElement)("canvas",{position:"absolute"},{class:"sigma-".concat(t)});return this.elements[t]=e,this.container.appendChild(e),e},e.prototype.createCanvasContext=function(t){var e=this.createCanvas(t);return this.canvasContexts[t]=e.getContext("2d",{preserveDrawingBuffer:!1,antialias:!1}),this},e.prototype.createWebGLContext=function(t,e){var r,i=this.createCanvas(t),n=o({preserveDrawingBuffer:!1,antialias:!1},e||{});return(r=i.getContext("webgl2",n))||(r=i.getContext("webgl",n)),r||(r=i.getContext("experimental-webgl",n)),this.webGLContexts[t]=r,this},e.prototype.bindCameraHandlers=function(){var t=this;return this.activeListeners.camera=function(){t._scheduleRefresh()},this.camera.on("updated",this.activeListeners.camera),this},e.prototype.mouseIsOnNode=function(t,e,r){var i=t.x,n=t.y,o=e.x,a=e.y;return i>o-r&&ia-r&&n=p&&(f=m,p=b)}}catch(t){r={error:t}}finally{try{v&&!v.done&&(i=g.return)&&i.call(g)}finally{if(r)throw r.error}}return f},e.prototype.process=function(t){var e=this;void 0===t&&(t=!1);var r=this.graph,i=this.settings,n=this.getDimensions(),o=[1/0,-1/0],a=[1/0,-1/0];this.quadtree.clear(),this.labelGrid.resizeAndClear(n,i.labelGridCellSize),this.highlightedNodes=new Set,this.nodeExtent=(0,f.graphExtent)(r),this.nodesWithForcedLabels=[],this.edgesWithForcedLabels=[];var s=new l.default,h=(0,f.matrixFromCamera)(s.getState(),this.getDimensions(),this.getGraphDimensions(),this.getSetting("stagePadding")||0);this.normalizationFunction=(0,f.createNormalizationFunction)(this.customBBox||this.nodeExtent);for(var c={},u=r.nodes(),d=0,p=u.length;do[1]&&(o[1]=y.zIndex))}for(var m in this.nodePrograms){if(!this.nodePrograms.hasOwnProperty(m))throw new Error('Sigma: could not find a suitable program for node type "'.concat(m,'"!'));t||this.nodePrograms[m].allocate(c[m]||0),c[m]=0}for(this.settings.zIndex&&o[0]!==o[1]&&(u=(0,f.zIndexOrdering)(o,(function(t){return e.nodeDataCache[t].zIndex}),u)),d=0,p=u.length;da[1]&&(a[1]=y.zIndex))}for(var m in this.edgePrograms){if(!this.edgePrograms.hasOwnProperty(m))throw new Error('Sigma: could not find a suitable program for edge type "'.concat(m,'"!'));t||this.edgePrograms[m].allocate(w[m]||0),w[m]=0}for(this.settings.zIndex&&a[0]!==a[1]&&(E=(0,f.zIndexOrdering)(a,(function(t){return e.edgeDataCache[t].zIndex}),E)),d=0,p=E.length;dthis.width+150||u<-50||u>this.height+50||(this.displayedLabels.add(a),this.settings.labelRenderer(r,o(o({key:a},s),{size:d,x:c,y:u}),this.settings))}}return this},e.prototype.renderEdgeLabels=function(){if(!this.settings.renderEdgeLabels)return this;var t=this.canvasContexts.edgeLabels;t.clearRect(0,0,this.width,this.height);for(var e=(0,p.edgeLabelsToDisplayFromNodes)({graph:this.graph,hoveredNode:this.hoveredNode,displayedNodeLabels:this.displayedLabels,highlightedNodes:this.highlightedNodes}).concat(this.edgesWithForcedLabels),r=new Set,i=0,n=e.length;i=1){for(var i in r){var o=r[i];for(var u in o)t.setNodeAttribute(i,u,o[u])}"function"==typeof a&&a()}else{for(var i in e=h(e),r){o=r[i];var d=c[i];for(var u in o)t.setNodeAttribute(i,u,o[u]*e+d[u]*(1-e))}p=(0,n.requestFrame)(g)}};return g(),function(){p&&(0,n.cancelFrame)(p)}}},634:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.HTML_COLORS=void 0,e.HTML_COLORS={black:"#000000",silver:"#C0C0C0",gray:"#808080",grey:"#808080",white:"#FFFFFF",maroon:"#800000",red:"#FF0000",purple:"#800080",fuchsia:"#FF00FF",green:"#008000",lime:"#00FF00",olive:"#808000",yellow:"#FFFF00",navy:"#000080",blue:"#0000FF",teal:"#008080",aqua:"#00FFFF",darkblue:"#00008B",mediumblue:"#0000CD",darkgreen:"#006400",darkcyan:"#008B8B",deepskyblue:"#00BFFF",darkturquoise:"#00CED1",mediumspringgreen:"#00FA9A",springgreen:"#00FF7F",cyan:"#00FFFF",midnightblue:"#191970",dodgerblue:"#1E90FF",lightseagreen:"#20B2AA",forestgreen:"#228B22",seagreen:"#2E8B57",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",limegreen:"#32CD32",mediumseagreen:"#3CB371",turquoise:"#40E0D0",royalblue:"#4169E1",steelblue:"#4682B4",darkslateblue:"#483D8B",mediumturquoise:"#48D1CC",indigo:"#4B0082",darkolivegreen:"#556B2F",cadetblue:"#5F9EA0",cornflowerblue:"#6495ED",rebeccapurple:"#663399",mediumaquamarine:"#66CDAA",dimgray:"#696969",dimgrey:"#696969",slateblue:"#6A5ACD",olivedrab:"#6B8E23",slategray:"#708090",slategrey:"#708090",lightslategray:"#778899",lightslategrey:"#778899",mediumslateblue:"#7B68EE",lawngreen:"#7CFC00",chartreuse:"#7FFF00",aquamarine:"#7FFFD4",skyblue:"#87CEEB",lightskyblue:"#87CEFA",blueviolet:"#8A2BE2",darkred:"#8B0000",darkmagenta:"#8B008B",saddlebrown:"#8B4513",darkseagreen:"#8FBC8F",lightgreen:"#90EE90",mediumpurple:"#9370DB",darkviolet:"#9400D3",palegreen:"#98FB98",darkorchid:"#9932CC",yellowgreen:"#9ACD32",sienna:"#A0522D",brown:"#A52A2A",darkgray:"#A9A9A9",darkgrey:"#A9A9A9",lightblue:"#ADD8E6",greenyellow:"#ADFF2F",paleturquoise:"#AFEEEE",lightsteelblue:"#B0C4DE",powderblue:"#B0E0E6",firebrick:"#B22222",darkgoldenrod:"#B8860B",mediumorchid:"#BA55D3",rosybrown:"#BC8F8F",darkkhaki:"#BDB76B",mediumvioletred:"#C71585",indianred:"#CD5C5C",peru:"#CD853F",chocolate:"#D2691E",tan:"#D2B48C",lightgray:"#D3D3D3",lightgrey:"#D3D3D3",thistle:"#D8BFD8",orchid:"#DA70D6",goldenrod:"#DAA520",palevioletred:"#DB7093",crimson:"#DC143C",gainsboro:"#DCDCDC",plum:"#DDA0DD",burlywood:"#DEB887",lightcyan:"#E0FFFF",lavender:"#E6E6FA",darksalmon:"#E9967A",violet:"#EE82EE",palegoldenrod:"#EEE8AA",lightcoral:"#F08080",khaki:"#F0E68C",aliceblue:"#F0F8FF",honeydew:"#F0FFF0",azure:"#F0FFFF",sandybrown:"#F4A460",wheat:"#F5DEB3",beige:"#F5F5DC",whitesmoke:"#F5F5F5",mintcream:"#F5FFFA",ghostwhite:"#F8F8FF",salmon:"#FA8072",antiquewhite:"#FAEBD7",linen:"#FAF0E6",lightgoldenrodyellow:"#FAFAD2",oldlace:"#FDF5E6",magenta:"#FF00FF",deeppink:"#FF1493",orangered:"#FF4500",tomato:"#FF6347",hotpink:"#FF69B4",coral:"#FF7F50",darkorange:"#FF8C00",lightsalmon:"#FFA07A",orange:"#FFA500",lightpink:"#FFB6C1",pink:"#FFC0CB",gold:"#FFD700",peachpuff:"#FFDAB9",navajowhite:"#FFDEAD",moccasin:"#FFE4B5",bisque:"#FFE4C4",mistyrose:"#FFE4E1",blanchedalmond:"#FFEBCD",papayawhip:"#FFEFD5",lavenderblush:"#FFF0F5",seashell:"#FFF5EE",cornsilk:"#FFF8DC",lemonchiffon:"#FFFACD",floralwhite:"#FFFAF0",snow:"#FFFAFA",lightyellow:"#FFFFE0",ivory:"#FFFFF0"}},358:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.cubicInOut=e.cubicOut=e.cubicIn=e.quadraticInOut=e.quadraticOut=e.quadraticIn=e.linear=void 0,e.linear=function(t){return t},e.quadraticIn=function(t){return t*t},e.quadraticOut=function(t){return t*(2-t)},e.quadraticInOut=function(t){return(t*=2)<1?.5*t*t:-.5*(--t*(t-2)-1)},e.cubicIn=function(t){return t*t*t},e.cubicOut=function(t){return--t*t*t+1},e.cubicInOut=function(t){return(t*=2)<1?.5*t*t*t:.5*((t-=2)*t*t+2)};var r={linear:e.linear,quadraticIn:e.quadraticIn,quadraticOut:e.quadraticOut,quadraticInOut:e.quadraticInOut,cubicIn:e.cubicIn,cubicOut:e.cubicOut,cubicInOut:e.cubicInOut};e.default=r},628:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.doEdgeCollideWithPoint=e.isPixelColored=void 0,e.isPixelColored=function(t,e,r){var i=new Uint8Array(4);return t.readPixels(e,t.drawingBufferHeight-r,1,1,t.RGBA,t.UNSIGNED_BYTE,i),i[3]>0},e.doEdgeCollideWithPoint=function(t,e,r,i,n,o,a){return!(tr+a&&t>n+a||e>i+a&&e>o+a||!(Math.abs((n-r)*(i-e)-(r-t)*(o-i))/Math.sqrt(Math.pow(n-r,2)+Math.pow(o-i,2))0)&&!(i=o.next()).done;)a.push(i.value)}catch(t){n={error:t}}finally{try{i&&!i.done&&(r=o.return)&&r.call(o)}finally{if(n)throw n.error}}return a},n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.validateGraph=e.canUse32BitsIndices=e.extractPixel=e.getMatrixImpact=e.matrixFromCamera=e.getCorrectionRatio=e.floatColor=e.floatArrayColor=e.parseColor=e.zIndexOrdering=e.createNormalizationFunction=e.graphExtent=e.getPixelRatio=e.createElement=e.cancelFrame=e.requestFrame=e.assignDeep=e.assign=e.isPlainObject=void 0;var o=n(r(186)),a=r(700),s=r(634);function h(t){return"object"==typeof t&&null!==t&&t.constructor===Object}e.isPlainObject=h,e.assign=function(t){for(var e=[],r=1;rr&&(r=a),sn&&(n=s)})),{x:[e,r],y:[i,n]}},e.createNormalizationFunction=function(t){var e=i(t.x,2),r=e[0],n=e[1],o=i(t.y,2),a=o[0],s=o[1],h=Math.max(n-r,s-a),l=(n+r)/2,c=(s+a)/2;(0===h||Math.abs(h)===1/0||isNaN(h))&&(h=1),isNaN(l)&&(l=0),isNaN(c)&&(c=0);var u=function(t){return{x:.5+(t.x-l)/h,y:.5+(t.y-c)/h}};return u.applyTo=function(t){t.x=.5+(t.x-l)/h,t.y=.5+(t.y-c)/h},u.inverse=function(t){return{x:l+h*(t.x-.5),y:c+h*(t.y-.5)}},u.ratio=h,u},e.zIndexOrdering=function(t,e,r){return r.sort((function(t,r){var i=e(t)||0,n=e(r)||0;return in?1:0}))};var l=new Int8Array(4),c=new Int32Array(l.buffer,0,1),u=new Float32Array(l.buffer,0,1),d=/^\s*rgba?\s*\(/,f=/^\s*rgba?\s*\(\s*([0-9]*)\s*,\s*([0-9]*)\s*,\s*([0-9]*)(?:\s*,\s*(.*)?)?\)\s*$/;function p(t){var e=0,r=0,i=0,n=1;if("#"===t[0])4===t.length?(e=parseInt(t.charAt(1)+t.charAt(1),16),r=parseInt(t.charAt(2)+t.charAt(2),16),i=parseInt(t.charAt(3)+t.charAt(3),16)):(e=parseInt(t.charAt(1)+t.charAt(2),16),r=parseInt(t.charAt(3)+t.charAt(4),16),i=parseInt(t.charAt(5)+t.charAt(6),16)),9===t.length&&(n=parseInt(t.charAt(7)+t.charAt(8),16)/255);else if(d.test(t)){var o=t.match(f);o&&(e=+o[1],r=+o[2],i=+o[3],o[4]&&(n=+o[4]))}return{r:e,g:r,b:i,a:n}}e.parseColor=p;var g={};for(var v in s.HTML_COLORS)g[v]=m(s.HTML_COLORS[v]),g[s.HTML_COLORS[v]]=g[v];function m(t){if(void 0!==g[t])return g[t];var e=p(t),r=e.r,i=e.g,n=e.b,o=e.a;o=255*o|0,c[0]=4278190079&(o<<24|n<<16|i<<8|r);var a=u[0];return g[t]=a,a}function y(t,e){var r=t.height/t.width,i=e.height/e.width;return r<1&&i>1||r>1&&i<1?1:Math.min(Math.max(i,1/i),Math.max(1/r,r))}e.floatArrayColor=function(t){var e=p(t=s.HTML_COLORS[t]||t),r=e.r,i=e.g,n=e.b,o=e.a;return new Float32Array([r/255,i/255,n/255,o])},e.floatColor=m,e.getCorrectionRatio=y,e.matrixFromCamera=function(t,e,r,i,n){var o=t.angle,s=t.ratio,h=t.x,l=t.y,c=e.width,u=e.height,d=(0,a.identity)(),f=Math.min(c,u)-2*i,p=y(e,r);return n?((0,a.multiply)(d,(0,a.translate)((0,a.identity)(),h,l)),(0,a.multiply)(d,(0,a.scale)((0,a.identity)(),s)),(0,a.multiply)(d,(0,a.rotate)((0,a.identity)(),o)),(0,a.multiply)(d,(0,a.scale)((0,a.identity)(),c/f/2/p,u/f/2/p))):((0,a.multiply)(d,(0,a.scale)((0,a.identity)(),f/c*2*p,f/u*2*p)),(0,a.multiply)(d,(0,a.rotate)((0,a.identity)(),-o)),(0,a.multiply)(d,(0,a.scale)((0,a.identity)(),1/s)),(0,a.multiply)(d,(0,a.translate)((0,a.identity)(),-h,-l))),d},e.getMatrixImpact=function(t,e,r){var i=(0,a.multiplyVec2)(t,{x:Math.cos(e.angle),y:Math.sin(e.angle)},0),n=i.x,o=i.y;return 1/Math.sqrt(Math.pow(n,2)+Math.pow(o,2))/r.width},e.extractPixel=function(t,e,r,i){var n=i||new Uint8Array(4);return t.readPixels(e,r,1,1,t.RGBA,t.UNSIGNED_BYTE,n),n},e.canUse32BitsIndices=function(t){return"undefined"!=typeof WebGL2RenderingContext&&t instanceof WebGL2RenderingContext||!!t.getExtension("OES_element_index_uint")},e.validateGraph=function(t){if(!(0,o.default)(t))throw new Error("Sigma: invalid graph instance.");t.forEachNode((function(t,e){if(!Number.isFinite(e.x)||!Number.isFinite(e.y))throw new Error("Sigma: Coordinates of node ".concat(t," are invalid. A node must have a numeric 'x' and 'y' attribute."))}))}},700:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.multiplyVec2=e.multiply=e.translate=e.rotate=e.scale=e.identity=void 0,e.identity=function(){return Float32Array.of(1,0,0,0,1,0,0,0,1)},e.scale=function(t,e,r){return t[0]=e,t[4]="number"==typeof r?r:e,t},e.rotate=function(t,e){var r=Math.sin(e),i=Math.cos(e);return t[0]=i,t[1]=r,t[3]=-r,t[4]=i,t},e.translate=function(t,e,r){return t[6]=e,t[7]=r,t},e.multiply=function(t,e){var r=t[0],i=t[1],n=t[2],o=t[3],a=t[4],s=t[5],h=t[6],l=t[7],c=t[8],u=e[0],d=e[1],f=e[2],p=e[3],g=e[4],v=e[5],m=e[6],y=e[7],b=e[8];return t[0]=u*r+d*o+f*h,t[1]=u*i+d*a+f*l,t[2]=u*n+d*s+f*c,t[3]=p*r+g*o+v*h,t[4]=p*i+g*a+v*l,t[5]=p*n+g*s+v*c,t[6]=m*r+y*o+b*h,t[7]=m*i+y*a+b*l,t[8]=m*n+y*s+b*c,t},e.multiplyVec2=function(t,e,r){void 0===r&&(r=1);var i=t[0],n=t[1],o=t[3],a=t[4],s=t[6],h=t[7],l=e.x,c=e.y;return{x:l*i+c*o+s*r,y:l*n+c*a+h*r}}}},e={};function r(i){var n=e[i];if(void 0!==n)return n.exports;var o=e[i]={exports:{}};return t[i].call(o.exports,o,o.exports,r),o.exports}r.d=(t,e)=>{for(var i in e)r.o(e,i)&&!r.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i=r(265);Sigma=i})();
\ No newline at end of file
diff --git a/static/styles.css b/static/styles.css
index 0d1df11..29f737c 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -9,7 +9,7 @@
 }
 
 /*
-! tailwindcss v3.4.1 | MIT License | https://tailwindcss.com
+! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
 */
 
 /*
@@ -221,6 +221,8 @@ textarea {
   /* 1 */
   line-height: inherit;
   /* 1 */
+  letter-spacing: inherit;
+  /* 1 */
   color: inherit;
   /* 1 */
   margin: 0;
@@ -244,9 +246,9 @@ select {
 */
 
 button,
-[type='button'],
-[type='reset'],
-[type='submit'] {
+input:where([type='button']),
+input:where([type='reset']),
+input:where([type='submit']) {
   -webkit-appearance: button;
   /* 1 */
   background-color: transparent;
@@ -509,6 +511,10 @@ html {
   --tw-backdrop-opacity:  ;
   --tw-backdrop-saturate:  ;
   --tw-backdrop-sepia:  ;
+  --tw-contain-size:  ;
+  --tw-contain-layout:  ;
+  --tw-contain-paint:  ;
+  --tw-contain-style:  ;
 }
 
 ::backdrop {
@@ -559,6 +565,10 @@ html {
   --tw-backdrop-opacity:  ;
   --tw-backdrop-saturate:  ;
   --tw-backdrop-sepia:  ;
+  --tw-contain-size:  ;
+  --tw-contain-layout:  ;
+  --tw-contain-paint:  ;
+  --tw-contain-style:  ;
 }
 
 .container {
@@ -595,17 +605,20 @@ html {
   }
 }
 
-.m-2 {
-  margin: 0.5rem;
+.absolute {
+  position: absolute;
 }
 
-.m-1 {
-  margin: 0.25rem;
+.relative {
+  position: relative;
 }
 
-.my-4 {
-  margin-top: 1rem;
-  margin-bottom: 1rem;
+.left-\[calc\(-1rem-1px\)\] {
+  left: calc(-1rem - 1px);
+}
+
+.top-4 {
+  top: 1rem;
 }
 
 .mx-auto {
@@ -618,25 +631,27 @@ html {
   margin-bottom: 0.25rem;
 }
 
-.my-8 {
-  margin-top: 2rem;
+.my-2 {
+  margin-top: 0.5rem;
+  margin-bottom: 0.5rem;
+}
+
+.my-3 {
+  margin-top: 0.75rem;
+  margin-bottom: 0.75rem;
+}
+
+.my-4 {
+  margin-top: 1rem;
+  margin-bottom: 1rem;
+}
+
+.mb-8 {
   margin-bottom: 2rem;
 }
 
-.ml-2 {
-  margin-left: 0.5rem;
-}
-
-.mt-1 {
-  margin-top: 0.25rem;
-}
-
-.mt-2 {
-  margin-top: 0.5rem;
-}
-
-.ml-1 {
-  margin-left: 0.25rem;
+.ml-8 {
+  margin-left: 2rem;
 }
 
 .block {
@@ -647,10 +662,26 @@ html {
   display: flex;
 }
 
+.grid {
+  display: grid;
+}
+
 .hidden {
   display: none;
 }
 
+.h-4 {
+  height: 1rem;
+}
+
+.h-\[600px\] {
+  height: 600px;
+}
+
+.h-\[60vh\] {
+  height: 60vh;
+}
+
 .h-full {
   height: 100%;
 }
@@ -665,6 +696,18 @@ html {
   height: min-content;
 }
 
+.h-\[80vh\] {
+  height: 80vh;
+}
+
+.h-16 {
+  height: 4rem;
+}
+
+.min-h-72 {
+  min-height: 18rem;
+}
+
 .min-h-max {
   min-height: -moz-max-content;
   min-height: max-content;
@@ -674,6 +717,10 @@ html {
   min-height: 100vh;
 }
 
+.w-4 {
+  width: 1rem;
+}
+
 .w-fit {
   width: -moz-fit-content;
   width: fit-content;
@@ -683,30 +730,6 @@ html {
   width: 100%;
 }
 
-.min-w-\[50vw\] {
-  min-width: 50vw;
-}
-
-.min-w-\[80vw\] {
-  min-width: 80vw;
-}
-
-.max-w-\[600px\] {
-  max-width: 600px;
-}
-
-.max-w-\[300px\] {
-  max-width: 300px;
-}
-
-.max-w-\[200px\] {
-  max-width: 200px;
-}
-
-.max-w-\[20rem\] {
-  max-width: 20rem;
-}
-
 .max-w-\[800px\] {
   max-width: 800px;
 }
@@ -715,8 +738,13 @@ html {
   flex: 1 1 0%;
 }
 
-.list-disc {
-  list-style-type: disc;
+.-translate-y-1\/2 {
+  --tw-translate-y: -50%;
+  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.grid-cols-\[auto_1fr\] {
+  grid-template-columns: auto 1fr;
 }
 
 .flex-col {
@@ -731,14 +759,26 @@ html {
   justify-content: center;
 }
 
-.border-2 {
-  border-width: 2px;
+.gap-y-1 {
+  row-gap: 0.25rem;
 }
 
 .border {
   border-width: 1px;
 }
 
+.border-2 {
+  border-width: 2px;
+}
+
+.border-4 {
+  border-width: 4px;
+}
+
+.border-l-2 {
+  border-left-width: 2px;
+}
+
 .border-r-0 {
   border-right-width: 0px;
 }
@@ -753,24 +793,19 @@ html {
   background-color: rgb(14 116 144 / var(--tw-bg-opacity));
 }
 
-.bg-emerald-400 {
+.bg-white {
   --tw-bg-opacity: 1;
-  background-color: rgb(52 211 153 / var(--tw-bg-opacity));
-}
-
-.bg-emerald-300 {
-  --tw-bg-opacity: 1;
-  background-color: rgb(110 231 183 / var(--tw-bg-opacity));
-}
-
-.p-4 {
-  padding: 1rem;
+  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
 }
 
 .p-2 {
   padding: 0.5rem;
 }
 
+.p-4 {
+  padding: 1rem;
+}
+
 .px-2 {
   padding-left: 0.5rem;
   padding-right: 0.5rem;
@@ -781,51 +816,22 @@ html {
   padding-bottom: 0.25rem;
 }
 
-.px-8 {
-  padding-left: 2rem;
-  padding-right: 2rem;
+.pl-2 {
+  padding-left: 0.5rem;
 }
 
-.py-8 {
-  padding-top: 2rem;
-  padding-bottom: 2rem;
-}
-
-.pl-0 {
-  padding-left: 0px;
-}
-
-.pl-4 {
-  padding-left: 1rem;
+.pt-4 {
+  padding-top: 1rem;
 }
 
 .text-center {
   text-align: center;
 }
 
-.align-middle {
-  vertical-align: middle;
-}
-
 .font-mono {
   font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
 }
 
-.text-4xl {
-  font-size: 2.25rem;
-  line-height: 2.5rem;
-}
-
-.text-xl {
-  font-size: 1.25rem;
-  line-height: 1.75rem;
-}
-
-.text-sm {
-  font-size: 0.875rem;
-  line-height: 1.25rem;
-}
-
 .text-2xl {
   font-size: 1.5rem;
   line-height: 2rem;
@@ -836,15 +842,39 @@ html {
   line-height: 2.25rem;
 }
 
+.text-4xl {
+  font-size: 2.25rem;
+  line-height: 2.5rem;
+}
+
 .text-5xl {
   font-size: 3rem;
   line-height: 1;
 }
 
+.text-sm {
+  font-size: 0.875rem;
+  line-height: 1.25rem;
+}
+
+.text-lg {
+  font-size: 1.125rem;
+  line-height: 1.75rem;
+}
+
+.text-xl {
+  font-size: 1.25rem;
+  line-height: 1.75rem;
+}
+
 .font-bold {
   font-weight: 700;
 }
 
+.italic {
+  font-style: italic;
+}
+
 .text-black {
   --tw-text-opacity: 1;
   color: rgb(0 0 0 / var(--tw-text-opacity));
diff --git a/tailwind.config.js b/tailwind.config.js
index 5aca841..35fc2b1 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,3 +1,3 @@
 module.exports = {
-    content: ["./views/**/*.liquid"],
-}
\ No newline at end of file
+	content: ["./views/**/*.liquid"],
+}
diff --git a/views/dependency.liquid b/views/dependency.liquid
index 5dd306f..e2bd4a0 100644
--- a/views/dependency.liquid
+++ b/views/dependency.liquid
@@ -1,13 +1,22 @@
-
-

{{name}} {{weight}}

-

{{summary}}

+
+
+ {% if has_parent %} +
+ {% endif %} + {{name}} {{weight}} +

{{summary}}

+
-
    - {% for dep in dependencies %} -
    - -

    {{dep.name}}

    -
    - {% endfor %} -
-
\ No newline at end of file + {% if dependencies != empty %} +
    + {% for dep in dependencies %} +
    + +

    {{dep.name}}

    +
    + {% endfor %} +
+ {% else %} +

No dependencies

+ {% endif %} +
diff --git a/views/fullgraph.liquid b/views/fullgraph.liquid new file mode 100644 index 0000000..13c4989 --- /dev/null +++ b/views/fullgraph.liquid @@ -0,0 +1,49 @@ +{% layout 'layout.liquid' %} + +{% block head %} + + + +Depyth +{% endblock %} + +{% block content %} +
+
+

Depyth

+
+ +

Analysis of your requirements.txt

+ +

General

+ +

Installing your requirements.txt would mean installing up to {{ nb_deps }} packages, for a total download size of around {{totalWeight.value}}.

+

Note: this estimation does not take into account platforms and architectures, and includes all optional packages.

+ +

Weight chart

+ + +
+ {% for package in packageByWeight %} +
+

{{package.name}}

+

{{package.humanWeight}} - {{ package.weight | divided_by: totalWeight.raw | times: 100 | round }}%

+
+ + {% endfor %} +
+ +

Dependency graph

+ +
+ + +
+{% endblock %} diff --git a/views/graph.liquid b/views/graph.liquid new file mode 100644 index 0000000..3f3feea --- /dev/null +++ b/views/graph.liquid @@ -0,0 +1,52 @@ +{% layout 'layout.liquid' %} + +{% block head %} + + + +Depyth +{% endblock %} + +{% block content %} +
+
+

Depyth

+

Dumb python packages things

+
+ +

{{packagename}}

+ +

General info

+ +

Installing this package means installing up to 0 packages

+

Installing this package means installing up to 0kb.

+ +

Dependency graph

+ +
+ + + + + + +
+{% endblock %} diff --git a/views/index.liquid b/views/index.liquid index 2a2ccdb..f28b1a7 100644 --- a/views/index.liquid +++ b/views/index.liquid @@ -1,46 +1,60 @@ {% layout 'layout.liquid' %} {% block head %} + + + Depyth {% endblock %} {% block content %} -
-

Depyth

- -
- -
- - -
-
+
+
+

Depyth

+

Dumb python packages thing

+
+ +

Inspect a requirements.txt file

+ +
+
+ + +
+ +
+ +

Analysing your (quite bloated) requirements...

+
+ +
+ + {% if false %} +

Inspect a package

+ +
+ + +
+ + +
+
+ {% endif %} -
- - - -
+
{% endblock %} diff --git a/views/layout.liquid b/views/layout.liquid index 2f7669c..3d14b71 100644 --- a/views/layout.liquid +++ b/views/layout.liquid @@ -9,7 +9,7 @@ - + {% block head %}{% endblock %} @@ -18,4 +18,4 @@ {% block content %}{% endblock %} - \ No newline at end of file +