diff --git a/.gitignore b/.gitignore index ff695f0..f06c106 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,10 @@ coverage.xml # documentation doc/ +site/ +_doc_mathimg/ +doc.md +doc.htex # PyBuilder target/ diff --git a/README.md b/README.md index 3dcdfe0..73d48b5 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,21 @@ linear systems, ideally with double precision. Install from PyPI with pip: ```bash +pip3 install meanas +``` + +Optional extras: + +- `meanas[test]`: pytest and coverage +- `meanas[docs]`: MkDocs-based documentation toolchain +- `meanas[examples]`: optional runtime dependencies used by the tracked examples +- `meanas[dev]`: the union of `test`, `docs`, and `examples`, plus local lint/docs-publish helpers + +Examples: +```bash +pip3 install 'meanas[test]' +pip3 install 'meanas[docs]' +pip3 install 'meanas[examples]' pip3 install 'meanas[dev]' ``` @@ -80,9 +95,13 @@ source my_venv/bin/activate # Install in-place (-e, editable) from ./meanas, including development dependencies ([dev]) pip3 install --user -e './meanas[dev]' -# Run tests +# Fast local iteration: excludes slower 3D/integration/example-smoke checks cd meanas -python3 -m pytest -rsxX | tee test_results.txt +python3 -m pytest -q -m "not complete" + +# Complete pre-commit confidence run: includes the slower integration tests and +# tracked example smoke tests +python3 -m pytest -q | tee test_results.txt ``` #### See also: @@ -94,6 +113,125 @@ python3 -m pytest -rsxX | tee test_results.txt ## Use -See `examples/` for some simple examples; you may need additional -packages such as [gridlock](https://mpxd.net/code/jan/gridlock) -to run the examples. +`meanas` is a collection of finite-difference electromagnetics tools: + +- `meanas.fdfd`: frequency-domain wave equations, sparse operators, SCPML, and + iterative solves for driven problems. +- `meanas.fdfd.waveguide_2d` / `meanas.fdfd.waveguide_3d`: waveguide mode + solvers, mode-source construction, and overlap windows for port-based + excitation and analysis. +- `meanas.fdtd`: Yee-step updates, CPML boundaries, flux/energy accounting, and + on-the-fly phasor extraction for comparing time-domain runs against FDFD. +- `meanas.fdmath`: low-level finite-difference operators, vectorization helpers, + and derivations shared by the FDTD and FDFD layers. + +For most users, the tracked examples under `examples/` are the right entry +point. The library API is primarily a toolbox; the module docstrings and API +pages are there to document the mathematical conventions and derivations behind +those tools. + +## Documentation + +API and workflow docs are generated from the package docstrings with +[MkDocs](https://www.mkdocs.org/), [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/), +and [mkdocstrings](https://mkdocstrings.github.io/). + +Install the docs toolchain with: + +```bash +pip3 install -e './meanas[docs]' +``` + +Then build the docs site with: + +```bash +./make_docs.sh +``` + +This produces: + +- a normal multi-page site under `site/` +- a combined printable single-page HTML site under `site/print_page/` +- an optional fully inlined `site/standalone.html` when `htmlark` is available + +The docs build uses a local MathJax bundle vendored under `docs/assets/`, so +the rendered HTML does not rely on external services for equation rendering. + +The tracked examples under `examples/` are the intended entry points for users: + +- `examples/fdtd.py`: broadband FDTD pulse excitation, phasor extraction, and a + residual check against the matching FDFD operator. +- `examples/waveguide.py`: waveguide mode solving, unidirectional mode-source + construction, overlap readout, and FDTD/FDFD comparison on a guided structure. +- `examples/waveguide_real.py`: real-valued continuous-wave FDTD on a straight + guide, with late-time monitor slices, guided-core windows, and mode-weighted + errors compared directly against real fields reconstructed from the matching + FDFD solution, plus a guided-mode / orthogonal-residual split. +- `examples/eme.py`: straight-interface mode matching / EME, including port + mode solving, interface scattering, and modal field visualization. +- `examples/eme_bend.py`: straight-to-bent waveguide mode matching with + cylindrical bend modes, interface scattering, and a cascaded bend-network + example built with `scikit-rf`. +- `examples/fdfd.py`: direct frequency-domain waveguide excitation and overlap / + Poynting analysis without a time-domain run. + +Several examples rely on optional packages such as +[gridlock](https://mpxd.net/code/jan/gridlock). + +### Frequency-domain waveguide workflow + +For a structure with a constant cross-section in one direction: + +1. Build `dxes` and the diagonal `epsilon` / `mu` distributions on the Yee grid. +2. Solve the port mode with `meanas.fdfd.waveguide_3d.solve_mode(...)`. +3. Build a unidirectional source with `compute_source(...)`. +4. Build a matching overlap window with `compute_overlap_e(...)`. +5. Solve the full FDFD problem and project the result onto the overlap window or + evaluate plane flux with `meanas.fdfd.functional.poynting_e_cross_h(...)`. + +### Time-domain phasor workflow + +For a broadband or continuous-wave FDTD run: + +1. Advance the fields with `meanas.fdtd.maxwell_e/maxwell_h` or + `updates_with_cpml(...)`. +2. Inject electric current using the same sign convention used throughout the + examples and library: `E -= dt * J / epsilon`. +3. Accumulate the desired phasor with `accumulate_phasor(...)` or the Yee-aware + wrappers `accumulate_phasor_e/h/j(...)`. +4. Build the matching FDFD operator on the stretched `dxes` if CPML/SCPML is + part of the simulation, and compare the extracted phasor to the FDFD field or + residual. + +This is the primary FDTD/FDFD equivalence workflow. The phasor extraction step +filters the time-domain run down to the guided `+\omega` content that FDFD +solves for directly, so it is the cleanest apples-to-apples comparison. + +### Real-field reconstruction workflow + +For a continuous-wave real-valued FDTD run: + +1. Build the analytic source phasor for the structure, for example with + `waveguide_3d.compute_source(...)`. +2. Run the real-valued FDTD simulation using the real part of that source. +3. Solve the matching FDFD problem from the analytic source phasor on the + stretched `dxes`. +4. Reconstruct late real `E/H/J` snapshots with + `reconstruct_real_e/h/j(...)` and compare those directly against the + real-valued FDTD fields, ideally on a monitor window or mode-weighted norm + centered on the guided field rather than on the full transverse plane. When + needed, split the monitor field into guided-mode and orthogonal residual + pieces to see whether the remaining mismatch is actually in the mode or in + weak nonguided tails. + +This is a stricter diagnostic, not the primary equivalence benchmark. A raw +monitor slice contains both the guided field and the remaining orthogonal +content on that plane, + +$$ E_{\text{monitor}} = E_{\text{guided}} + E_{\text{residual}} , $$ + +so its full-plane instantaneous error is naturally noisier than the extracted +phasor comparison even when the underlying guided `+\omega` content matches +well. + +`examples/waveguide_real.py` is the reference implementation of this workflow. diff --git a/docs/api/eigensolvers.md b/docs/api/eigensolvers.md new file mode 100644 index 0000000..7f16e01 --- /dev/null +++ b/docs/api/eigensolvers.md @@ -0,0 +1,3 @@ +# eigensolvers + +::: meanas.eigensolvers diff --git a/docs/api/fdfd.md b/docs/api/fdfd.md new file mode 100644 index 0000000..e47c278 --- /dev/null +++ b/docs/api/fdfd.md @@ -0,0 +1,15 @@ +# fdfd + +::: meanas.fdfd + +## Core operator layers + +::: meanas.fdfd.functional + +::: meanas.fdfd.operators + +::: meanas.fdfd.solvers + +::: meanas.fdfd.scpml + +::: meanas.fdfd.farfield diff --git a/docs/api/fdmath.md b/docs/api/fdmath.md new file mode 100644 index 0000000..3623207 --- /dev/null +++ b/docs/api/fdmath.md @@ -0,0 +1,13 @@ +# fdmath + +::: meanas.fdmath + +## Functional and sparse operators + +::: meanas.fdmath.functional + +::: meanas.fdmath.operators + +::: meanas.fdmath.vectorization + +::: meanas.fdmath.types diff --git a/docs/api/fdtd.md b/docs/api/fdtd.md new file mode 100644 index 0000000..3e1823c --- /dev/null +++ b/docs/api/fdtd.md @@ -0,0 +1,15 @@ +# fdtd + +::: meanas.fdtd + +## Core update and analysis helpers + +::: meanas.fdtd.base + +::: meanas.fdtd.pml + +::: meanas.fdtd.boundaries + +::: meanas.fdtd.energy + +::: meanas.fdtd.phasor diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 0000000..d30ae80 --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,14 @@ +# API Overview + +The package is documented directly from its docstrings. The most useful entry +points are: + +- [meanas](meanas.md): top-level package overview +- [eigensolvers](eigensolvers.md): generic eigenvalue utilities used by the mode solvers +- [fdfd](fdfd.md): frequency-domain operators, sources, PML, solvers, and far-field transforms +- [waveguides](waveguides.md): straight, cylindrical, and 3D waveguide mode helpers +- [fdtd](fdtd.md): timestepping, CPML, energy/flux helpers, and phasor extraction +- [fdmath](fdmath.md): shared discrete operators, vectorization helpers, and derivation background + +The waveguide and FDTD pages are the best places to start if you want the +mathematical derivations rather than just the callable reference. diff --git a/docs/api/meanas.md b/docs/api/meanas.md new file mode 100644 index 0000000..d5c5f4e --- /dev/null +++ b/docs/api/meanas.md @@ -0,0 +1,3 @@ +# meanas + +::: meanas diff --git a/docs/api/waveguides.md b/docs/api/waveguides.md new file mode 100644 index 0000000..834614c --- /dev/null +++ b/docs/api/waveguides.md @@ -0,0 +1,7 @@ +# waveguides + +::: meanas.fdfd.waveguide_2d + +::: meanas.fdfd.waveguide_3d + +::: meanas.fdfd.waveguide_cyl diff --git a/docs/assets/vendor/mathjax/core.js b/docs/assets/vendor/mathjax/core.js new file mode 100644 index 0000000..8b9db53 --- /dev/null +++ b/docs/assets/vendor/mathjax/core.js @@ -0,0 +1 @@ +!function(){"use strict";var t,e,r,n,o,i,s,a,l,u,c,p,f,h,d,y,O,M,E,v,b,m,g,L,N,R,T,S,A,C,_,x,I,w,P,j,D,B,k,X,H,W,F,q,J,G,z,V,U,K,$,Y,Z,Q,tt,et,rt,nt,ot,it,st,at,lt,ut,ct,pt,ft,ht,dt,yt,Ot,Mt,Et,vt,bt,mt,gt,Lt={444:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.HTMLAdaptor=void 0;var s=function(t){function e(e){var r=t.call(this,e.document)||this;return r.window=e,r.parser=new e.DOMParser,r}return o(e,t),e.prototype.parse=function(t,e){return void 0===e&&(e="text/html"),this.parser.parseFromString(t,e)},e.prototype.create=function(t,e){return e?this.document.createElementNS(e,t):this.document.createElement(t)},e.prototype.text=function(t){return this.document.createTextNode(t)},e.prototype.head=function(t){return t.head},e.prototype.body=function(t){return t.body},e.prototype.root=function(t){return t.documentElement},e.prototype.doctype=function(t){return""},e.prototype.tags=function(t,e,r){void 0===r&&(r=null);var n=r?t.getElementsByTagNameNS(r,e):t.getElementsByTagName(e);return Array.from(n)},e.prototype.getElements=function(t,e){var r,n,o=[];try{for(var s=i(t),a=s.next();!a.done;a=s.next()){var l=a.value;"string"==typeof l?o=o.concat(Array.from(this.document.querySelectorAll(l))):Array.isArray(l)||l instanceof this.window.NodeList||l instanceof this.window.HTMLCollection?o=o.concat(Array.from(l)):o.push(l)}}catch(t){r={error:t}}finally{try{a&&!a.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}return o},e.prototype.contains=function(t,e){return t.contains(e)},e.prototype.parent=function(t){return t.parentNode},e.prototype.append=function(t,e){return t.appendChild(e)},e.prototype.insert=function(t,e){return this.parent(e).insertBefore(t,e)},e.prototype.remove=function(t){return this.parent(t).removeChild(t)},e.prototype.replace=function(t,e){return this.parent(e).replaceChild(t,e)},e.prototype.clone=function(t){return t.cloneNode(!0)},e.prototype.split=function(t,e){return t.splitText(e)},e.prototype.next=function(t){return t.nextSibling},e.prototype.previous=function(t){return t.previousSibling},e.prototype.firstChild=function(t){return t.firstChild},e.prototype.lastChild=function(t){return t.lastChild},e.prototype.childNodes=function(t){return Array.from(t.childNodes)},e.prototype.childNode=function(t,e){return t.childNodes[e]},e.prototype.kind=function(t){var e=t.nodeType;return 1===e||3===e||8===e?t.nodeName.toLowerCase():""},e.prototype.value=function(t){return t.nodeValue||""},e.prototype.textContent=function(t){return t.textContent},e.prototype.innerHTML=function(t){return t.innerHTML},e.prototype.outerHTML=function(t){return t.outerHTML},e.prototype.serializeXML=function(t){return(new this.window.XMLSerializer).serializeToString(t)},e.prototype.setAttribute=function(t,e,r,n){return void 0===n&&(n=null),n?(e=n.replace(/.*\//,"")+":"+e.replace(/^.*:/,""),t.setAttributeNS(n,e,r)):t.setAttribute(e,r)},e.prototype.getAttribute=function(t,e){return t.getAttribute(e)},e.prototype.removeAttribute=function(t,e){return t.removeAttribute(e)},e.prototype.hasAttribute=function(t,e){return t.hasAttribute(e)},e.prototype.allAttributes=function(t){return Array.from(t.attributes).map((function(t){return{name:t.name,value:t.value}}))},e.prototype.addClass=function(t,e){t.classList?t.classList.add(e):t.className=(t.className+" "+e).trim()},e.prototype.removeClass=function(t,e){t.classList?t.classList.remove(e):t.className=t.className.split(/ /).filter((function(t){return t!==e})).join(" ")},e.prototype.hasClass=function(t,e){return t.classList?t.classList.contains(e):t.className.split(/ /).indexOf(e)>=0},e.prototype.setStyle=function(t,e,r){t.style[e]=r},e.prototype.getStyle=function(t,e){return t.style[e]},e.prototype.allStyles=function(t){return t.style.cssText},e.prototype.fontSize=function(t){var e=this.window.getComputedStyle(t);return parseFloat(e.fontSize)},e.prototype.fontFamily=function(t){return this.window.getComputedStyle(t).fontFamily||""},e.prototype.nodeSize=function(t,e,r){if(void 0===e&&(e=1),void 0===r&&(r=!1),r&&t.getBBox){var n=t.getBBox();return[n.width/e,n.height/e]}return[t.offsetWidth/e,t.offsetHeight/e]},e.prototype.nodeBBox=function(t){var e=t.getBoundingClientRect();return{left:e.left,right:e.right,top:e.top,bottom:e.bottom}},e}(r(5009).AbstractDOMAdaptor);e.HTMLAdaptor=s},6191:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.browserAdaptor=void 0;var n=r(444);e.browserAdaptor=function(){return new n.HTMLAdaptor(window)}},9515:function(t,e,r){var n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};function o(t){return"object"==typeof t&&null!==t}function i(t,e){var r,s;try{for(var a=n(Object.keys(e)),l=a.next();!l.done;l=a.next()){var u=l.value;"__esModule"!==u&&(!o(t[u])||!o(e[u])||e[u]instanceof Promise?null!==e[u]&&void 0!==e[u]&&(t[u]=e[u]):i(t[u],e[u]))}}catch(t){r={error:t}}finally{try{l&&!l.done&&(s=a.return)&&s.call(a)}finally{if(r)throw r.error}}return t}Object.defineProperty(e,"__esModule",{value:!0}),e.MathJax=e.combineWithMathJax=e.combineDefaults=e.combineConfig=e.isObject=void 0,e.isObject=o,e.combineConfig=i,e.combineDefaults=function t(e,r,i){var s,a;e[r]||(e[r]={}),e=e[r];try{for(var l=n(Object.keys(i)),u=l.next();!u.done;u=l.next()){var c=u.value;o(e[c])&&o(i[c])?t(e,c,i[c]):null==e[c]&&null!=i[c]&&(e[c]=i[c])}}catch(t){s={error:t}}finally{try{u&&!u.done&&(a=l.return)&&a.call(l)}finally{if(s)throw s.error}}return e},e.combineWithMathJax=function(t){return i(e.MathJax,t)},void 0===r.g.MathJax&&(r.g.MathJax={}),r.g.MathJax.version||(r.g.MathJax={version:"3.1.4",_:{},config:r.g.MathJax}),e.MathJax=r.g.MathJax},5009:function(t,e){var r=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractDOMAdaptor=void 0;var n=function(){function t(t){void 0===t&&(t=null),this.document=t}return t.prototype.node=function(t,e,n,o){var i,s;void 0===e&&(e={}),void 0===n&&(n=[]);var a=this.create(t,o);this.setAttributes(a,e);try{for(var l=r(n),u=l.next();!u.done;u=l.next()){var c=u.value;this.append(a,c)}}catch(t){i={error:t}}finally{try{u&&!u.done&&(s=l.return)&&s.call(l)}finally{if(i)throw i.error}}return a},t.prototype.setAttributes=function(t,e){var n,o,i,s,a,l;if(e.style&&"string"!=typeof e.style)try{for(var u=r(Object.keys(e.style)),c=u.next();!c.done;c=u.next()){var p=c.value;this.setStyle(t,p.replace(/-([a-z])/g,(function(t,e){return e.toUpperCase()})),e.style[p])}}catch(t){n={error:t}}finally{try{c&&!c.done&&(o=u.return)&&o.call(u)}finally{if(n)throw n.error}}if(e.properties)try{for(var f=r(Object.keys(e.properties)),h=f.next();!h.done;h=f.next()){t[p=h.value]=e.properties[p]}}catch(t){i={error:t}}finally{try{h&&!h.done&&(s=f.return)&&s.call(f)}finally{if(i)throw i.error}}try{for(var d=r(Object.keys(e)),y=d.next();!y.done;y=d.next()){"style"===(p=y.value)&&"string"!=typeof e.style||"properties"===p||this.setAttribute(t,p,e[p])}}catch(t){a={error:t}}finally{try{y&&!y.done&&(l=d.return)&&l.call(d)}finally{if(a)throw a.error}}},t.prototype.replace=function(t,e){return this.insert(t,e),this.remove(e),e},t.prototype.childNode=function(t,e){return this.childNodes(t)[e]},t.prototype.allClasses=function(t){var e=this.getAttribute(t,"class");return e?e.replace(/ +/g," ").replace(/^ /,"").replace(/ $/,"").split(/ /):[]},t}();e.AbstractDOMAdaptor=n},3494:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractFindMath=void 0;var n=r(7233),o=function(){function t(t){var e=this.constructor;this.options=n.userOptions(n.defaultOptions({},e.OPTIONS),t)}return t.OPTIONS={},t}();e.AbstractFindMath=o},3670:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractHandler=void 0;var i=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e}(r(5722).AbstractMathDocument),s=function(){function t(t,e){void 0===e&&(e=5),this.documentClass=i,this.adaptor=t,this.priority=e}return Object.defineProperty(t.prototype,"name",{get:function(){return this.constructor.NAME},enumerable:!1,configurable:!0}),t.prototype.handlesDocument=function(t){return!1},t.prototype.create=function(t,e){return new this.documentClass(t,this.adaptor,e)},t.NAME="generic",t}();e.AbstractHandler=s},805:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.HandlerList=void 0;var s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.register=function(t){return this.add(t,t.priority)},e.prototype.unregister=function(t){this.remove(t)},e.prototype.handlesDocument=function(t){var e,r;try{for(var n=i(this),o=n.next();!o.done;o=n.next()){var s=o.value.item;if(s.handlesDocument(t))return s}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}throw new Error("Can't find handler for document")},e.prototype.document=function(t,e){return void 0===e&&(e=null),this.handlesDocument(t).create(t,e)},e}(r(8666).PrioritizedList);e.HandlerList=s},9206:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractInputJax=void 0;var n=r(7233),o=r(7525),i=function(){function t(t){void 0===t&&(t={}),this.adaptor=null,this.mmlFactory=null;var e=this.constructor;this.options=n.userOptions(n.defaultOptions({},e.OPTIONS),t),this.preFilters=new o.FunctionList,this.postFilters=new o.FunctionList}return Object.defineProperty(t.prototype,"name",{get:function(){return this.constructor.NAME},enumerable:!1,configurable:!0}),t.prototype.setAdaptor=function(t){this.adaptor=t},t.prototype.setMmlFactory=function(t){this.mmlFactory=t},t.prototype.initialize=function(){},t.prototype.reset=function(){for(var t=[],e=0;e=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},a=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=e&&a.item.renderDoc(t))return}}catch(t){r={error:t}}finally{try{s&&!s.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}},e.prototype.renderMath=function(t,e,r){var n,o;void 0===r&&(r=f.STATE.UNPROCESSED);try{for(var s=i(this.items),a=s.next();!a.done;a=s.next()){var l=a.value;if(l.priority>=r&&l.item.renderMath(t,e))return}}catch(t){n={error:t}}finally{try{a&&!a.done&&(o=s.return)&&o.call(s)}finally{if(n)throw n.error}}},e.prototype.renderConvert=function(t,e,r){var n,o;void 0===r&&(r=f.STATE.LAST);try{for(var s=i(this.items),a=s.next();!a.done;a=s.next()){var l=a.value;if(l.priority>r)return;if(l.item.convert&&l.item.renderMath(t,e))return}}catch(t){n={error:t}}finally{try{a&&!a.done&&(o=s.return)&&o.call(s)}finally{if(n)throw n.error}}},e.prototype.findID=function(t){var e,r;try{for(var n=i(this.items),o=n.next();!o.done;o=n.next()){var s=o.value;if(s.item.id===t)return s.item}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}return null},e}(r(8666).PrioritizedList);e.RenderList=y,e.resetOptions={all:!1,processed:!1,inputJax:null,outputJax:null},e.resetAllOptions={all:!0,processed:!0,inputJax:[],outputJax:[]};var O=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.compile=function(t){return null},e}(u.AbstractInputJax),M=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.typeset=function(t,e){return void 0===e&&(e=null),null},e.prototype.escaped=function(t,e){return null},e}(c.AbstractOutputJax),E=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e}(p.AbstractMathList),v=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e}(f.AbstractMathItem),b=function(){function t(e,r,n){var o=this,i=this.constructor;this.document=e,this.options=l.userOptions(l.defaultOptions({},i.OPTIONS),n),this.math=new(this.options.MathList||E),this.renderActions=y.create(this.options.renderActions),this.processed=new t.ProcessBits,this.outputJax=this.options.OutputJax||new M;var s=this.options.InputJax||[new O];Array.isArray(s)||(s=[s]),this.inputJax=s,this.adaptor=r,this.outputJax.setAdaptor(r),this.inputJax.map((function(t){return t.setAdaptor(r)})),this.mmlFactory=this.options.MmlFactory||new h.MmlFactory,this.inputJax.map((function(t){return t.setMmlFactory(o.mmlFactory)})),this.outputJax.initialize(),this.inputJax.map((function(t){return t.initialize()}))}return Object.defineProperty(t.prototype,"kind",{get:function(){return this.constructor.KIND},enumerable:!1,configurable:!0}),t.prototype.addRenderAction=function(t){for(var e=[],r=1;r=r&&this.state(r-1),t.renderActions.renderMath(this,t,r)},t.prototype.convert=function(t,r){void 0===r&&(r=e.STATE.LAST),t.renderActions.renderConvert(this,t,r)},t.prototype.compile=function(t){this.state()=e.STATE.INSERTED&&this.removeFromDocument(r),t=e.STATE.TYPESET&&(this.outputData={}),t=e.STATE.COMPILED&&(this.inputData={}),this._state=t),this._state},t.prototype.reset=function(t){void 0===t&&(t=!1),this.state(e.STATE.UNPROCESSED,t)},t}();e.AbstractMathItem=r,e.STATE={UNPROCESSED:0,FINDMATH:10,COMPILED:20,CONVERT:100,METRICS:110,RERENDER:125,TYPESET:150,INSERTED:200,LAST:1e4},e.newState=function(t,r){if(t in e.STATE)throw Error("State "+t+" already exists");e.STATE[t]=r}},9e3:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractMathList=void 0;var i=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.isBefore=function(t,e){return t.start.i=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.Attributes=e.INHERIT=void 0,e.INHERIT="_inherit_";var n=function(){function t(t,e){this.global=e,this.defaults=Object.create(e),this.inherited=Object.create(this.defaults),this.attributes=Object.create(this.inherited),Object.assign(this.defaults,t)}return t.prototype.set=function(t,e){this.attributes[t]=e},t.prototype.setList=function(t){Object.assign(this.attributes,t)},t.prototype.get=function(t){var r=this.attributes[t];return r===e.INHERIT&&(r=this.global[t]),r},t.prototype.getExplicit=function(t){if(this.attributes.hasOwnProperty(t))return this.attributes[t]},t.prototype.getList=function(){for(var t,e,n=[],o=0;o=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MathMLVisitor=void 0;var s=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.document=null,e}return o(e,t),e.prototype.visitTree=function(t,e){this.document=e;var r=e.createElement("top");return this.visitNode(t,r),this.document=null,r.firstChild},e.prototype.visitTextNode=function(t,e){e.appendChild(this.document.createTextNode(t.getText()))},e.prototype.visitXMLNode=function(t,e){e.appendChild(t.getXML().cloneNode(!0))},e.prototype.visitInferredMrowNode=function(t,e){var r,n;try{for(var o=i(t.childNodes),s=o.next();!s.done;s=o.next()){var a=s.value;this.visitNode(a,e)}}catch(t){r={error:t}}finally{try{s&&!s.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}},e.prototype.visitDefault=function(t,e){var r,n,o=this.document.createElement(t.kind);this.addAttributes(t,o);try{for(var s=i(t.childNodes),a=s.next();!a.done;a=s.next()){var l=a.value;this.visitNode(l,o)}}catch(t){r={error:t}}finally{try{a&&!a.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}e.appendChild(o)},e.prototype.addAttributes=function(t,e){var r,n,o=t.attributes,s=o.getExplicitNames();try{for(var a=i(s),l=a.next();!l.done;l=a.next()){var u=l.value;e.setAttribute(u,o.getExplicit(u).toString())}}catch(t){r={error:t}}finally{try{l&&!l.done&&(n=a.return)&&n.call(a)}finally{if(r)throw r.error}}},e}(r(6325).MmlVisitor);e.MathMLVisitor=s},3909:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.MmlFactory=void 0;var i=r(7860),s=r(6336),a=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"MML",{get:function(){return this.node},enumerable:!1,configurable:!0}),e.defaultNodes=s.MML,e}(i.AbstractNodeFactory);e.MmlFactory=a},9007:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},a=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s};Object.defineProperty(e,"__esModule",{value:!0}),e.XMLNode=e.TextNode=e.AbstractMmlEmptyNode=e.AbstractMmlBaseNode=e.AbstractMmlLayoutNode=e.AbstractMmlTokenNode=e.AbstractMmlNode=e.indentAttributes=e.TEXCLASSNAMES=e.TEXCLASS=void 0;var l=r(91),u=r(4596);e.TEXCLASS={ORD:0,OP:1,BIN:2,REL:3,OPEN:4,CLOSE:5,PUNCT:6,INNER:7,VCENTER:8,NONE:-1},e.TEXCLASSNAMES=["ORD","OP","BIN","REL","OPEN","CLOSE","PUNCT","INNER","VCENTER"];var c=["","thinmathspace","mediummathspace","thickmathspace"],p=[[0,-1,2,3,0,0,0,1],[-1,-1,0,3,0,0,0,1],[2,2,0,0,2,0,0,2],[3,3,0,0,3,0,0,3],[0,0,0,0,0,0,0,0],[0,-1,2,3,0,0,0,1],[1,1,0,1,1,1,1,1],[1,-1,2,3,1,0,1,1]];e.indentAttributes=["indentalign","indentalignfirst","indentshift","indentshiftfirst"];var f=function(t){function r(e,r,n){void 0===r&&(r={}),void 0===n&&(n=[]);var o=t.call(this,e)||this;return o.prevClass=null,o.prevLevel=null,o.texclass=null,o.arity<0&&(o.childNodes=[e.create("inferredMrow")],o.childNodes[0].parent=o),o.setChildren(n),o.attributes=new l.Attributes(e.getNodeClass(o.kind).defaults,e.getNodeClass("math").defaults),o.attributes.setList(r),o}return o(r,t),Object.defineProperty(r.prototype,"texClass",{get:function(){return this.texclass},set:function(t){this.texclass=t},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isToken",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isEmbellished",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isSpacelike",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"linebreakContainer",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"hasNewLine",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"arity",{get:function(){return 1/0},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isInferred",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"Parent",{get:function(){for(var t=this.parent;t&&t.notParent;)t=t.Parent;return t},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"notParent",{get:function(){return!1},enumerable:!1,configurable:!0}),r.prototype.setChildren=function(e){return this.arity<0?this.childNodes[0].setChildren(e):t.prototype.setChildren.call(this,e)},r.prototype.appendChild=function(e){var r,n,o=this;if(this.arity<0)return this.childNodes[0].appendChild(e),e;if(e.isInferred){if(this.arity===1/0)return e.childNodes.forEach((function(e){return t.prototype.appendChild.call(o,e)})),e;var i=e;(e=this.factory.create("mrow")).setChildren(i.childNodes),e.attributes=i.attributes;try{for(var a=s(i.getPropertyNames()),l=a.next();!l.done;l=a.next()){var u=l.value;e.setProperty(u,i.getProperty(u))}}catch(t){r={error:t}}finally{try{l&&!l.done&&(n=a.return)&&n.call(a)}finally{if(r)throw r.error}}}return t.prototype.appendChild.call(this,e)},r.prototype.replaceChild=function(e,r){return this.arity<0?(this.childNodes[0].replaceChild(e,r),e):t.prototype.replaceChild.call(this,e,r)},r.prototype.core=function(){return this},r.prototype.coreMO=function(){return this},r.prototype.coreIndex=function(){return 0},r.prototype.childPosition=function(){for(var t,e,r=this,n=r.parent;n&&n.notParent;)r=n,n=n.parent;if(n){var o=0;try{for(var i=s(n.childNodes),a=i.next();!a.done;a=i.next()){if(a.value===r)return o;o++}}catch(e){t={error:e}}finally{try{a&&!a.done&&(e=i.return)&&e.call(i)}finally{if(t)throw t.error}}}return null},r.prototype.setTeXclass=function(t){return this.getPrevClass(t),null!=this.texClass?this:t},r.prototype.updateTeXclass=function(t){t&&(this.prevClass=t.prevClass,this.prevLevel=t.prevLevel,t.prevClass=t.prevLevel=null,this.texClass=t.texClass)},r.prototype.getPrevClass=function(t){t&&(this.prevClass=t.texClass,this.prevLevel=t.attributes.get("scriptlevel"))},r.prototype.texSpacing=function(){var t=null!=this.prevClass?this.prevClass:e.TEXCLASS.NONE,r=this.texClass||e.TEXCLASS.ORD;if(t===e.TEXCLASS.NONE||r===e.TEXCLASS.NONE)return"";t===e.TEXCLASS.VCENTER&&(t=e.TEXCLASS.ORD),r===e.TEXCLASS.VCENTER&&(r=e.TEXCLASS.ORD);var n=p[t][r];return(this.prevLevel>0||this.attributes.get("scriptlevel")>0)&&n>=0?"":c[Math.abs(n)]},r.prototype.hasSpacingAttributes=function(){return this.isEmbellished&&this.coreMO().hasSpacingAttributes()},r.prototype.setInheritedAttributes=function(t,e,n,o){var i,l;void 0===t&&(t={}),void 0===e&&(e=!1),void 0===n&&(n=0),void 0===o&&(o=!1);var u=this.attributes.getAllDefaults();try{for(var c=s(Object.keys(t)),p=c.next();!p.done;p=c.next()){var f=p.value;if(u.hasOwnProperty(f)||r.alwaysInherit.hasOwnProperty(f)){var h=a(t[f],2),d=h[0],y=h[1];((r.noInherit[d]||{})[this.kind]||{})[f]||this.attributes.setInherited(f,y)}}}catch(t){i={error:t}}finally{try{p&&!p.done&&(l=c.return)&&l.call(c)}finally{if(i)throw i.error}}void 0===this.attributes.getExplicit("displaystyle")&&this.attributes.setInherited("displaystyle",e),void 0===this.attributes.getExplicit("scriptlevel")&&this.attributes.setInherited("scriptlevel",n),o&&this.setProperty("texprimestyle",o);var O=this.arity;if(O>=0&&O!==1/0&&(1===O&&0===this.childNodes.length||1!==O&&this.childNodes.length!==O))if(O=0&&e!==1/0&&(1===e&&0===this.childNodes.length||1!==e&&this.childNodes.length!==e)&&this.mError('Wrong number of children for "'+this.kind+'" node',t,!0),this.verifyChildren(t)}},r.prototype.verifyAttributes=function(t){var e,r;if(t.checkAttributes){var n=this.attributes,o=[];try{for(var i=s(n.getExplicitNames()),a=i.next();!a.done;a=i.next()){var l=a.value;"data-"===l.substr(0,5)||void 0!==n.getDefault(l)||l.match(/^(?:class|style|id|(?:xlink:)?href)$/)||o.push(l)}}catch(t){e={error:t}}finally{try{a&&!a.done&&(r=i.return)&&r.call(i)}finally{if(e)throw e.error}}o.length&&this.mError("Unknown attributes for "+this.kind+" node: "+o.join(", "),t)}},r.prototype.verifyChildren=function(t){var e,r;try{for(var n=s(this.childNodes),o=n.next();!o.done;o=n.next()){o.value.verifyTree(t)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}},r.prototype.mError=function(t,e,r){if(void 0===r&&(r=!1),this.parent&&this.parent.isKind("merror"))return null;var n=this.factory.create("merror");if(e.fullErrors||r){var o=this.factory.create("mtext"),i=this.factory.create("text");i.setText(e.fullErrors?t:this.kind),o.appendChild(i),n.appendChild(o),this.parent.replaceChild(n,this)}else this.parent.replaceChild(n,this),n.appendChild(this);return n},r.defaults={mathbackground:l.INHERIT,mathcolor:l.INHERIT,mathsize:l.INHERIT,dir:l.INHERIT},r.noInherit={mstyle:{mpadded:{width:!0,height:!0,depth:!0,lspace:!0,voffset:!0},mtable:{width:!0,height:!0,depth:!0,align:!0}},maligngroup:{mrow:{groupalign:!0},mtable:{groupalign:!0}}},r.alwaysInherit={scriptminsize:!0,scriptsizemultiplier:!0},r.verifyDefaults={checkArity:!0,checkAttributes:!1,fullErrors:!1,fixMmultiscripts:!0,fixMtables:!0},r}(u.AbstractNode);e.AbstractMmlNode=f;var h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"isToken",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.getText=function(){var t,e,r="";try{for(var n=s(this.childNodes),o=n.next();!o.done;o=n.next()){var i=o.value;i instanceof M&&(r+=i.getText())}}catch(e){t={error:e}}finally{try{o&&!o.done&&(e=n.return)&&e.call(n)}finally{if(t)throw t.error}}return r},e.prototype.setChildInheritedAttributes=function(t,e,r,n){var o,i;try{for(var a=s(this.childNodes),l=a.next();!l.done;l=a.next()){var u=l.value;u instanceof f&&u.setInheritedAttributes(t,e,r,n)}}catch(t){o={error:t}}finally{try{l&&!l.done&&(i=a.return)&&i.call(a)}finally{if(o)throw o.error}}},e.prototype.walkTree=function(t,e){var r,n;t(this,e);try{for(var o=s(this.childNodes),i=o.next();!i.done;i=o.next()){var a=i.value;a instanceof f&&a.walkTree(t,e)}}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}return e},e.defaults=i(i({},f.defaults),{mathvariant:"normal",mathsize:l.INHERIT}),e}(f);e.AbstractMmlTokenNode=h;var d=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"isSpacelike",{get:function(){return this.childNodes[0].isSpacelike},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isEmbellished",{get:function(){return this.childNodes[0].isEmbellished},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"arity",{get:function(){return-1},enumerable:!1,configurable:!0}),e.prototype.core=function(){return this.childNodes[0]},e.prototype.coreMO=function(){return this.childNodes[0].coreMO()},e.prototype.setTeXclass=function(t){return t=this.childNodes[0].setTeXclass(t),this.updateTeXclass(this.childNodes[0]),t},e.defaults=f.defaults,e}(f);e.AbstractMmlLayoutNode=d;var y=function(t){function r(){return null!==t&&t.apply(this,arguments)||this}return o(r,t),Object.defineProperty(r.prototype,"isEmbellished",{get:function(){return this.childNodes[0].isEmbellished},enumerable:!1,configurable:!0}),r.prototype.core=function(){return this.childNodes[0]},r.prototype.coreMO=function(){return this.childNodes[0].coreMO()},r.prototype.setTeXclass=function(t){var r,n;this.getPrevClass(t),this.texClass=e.TEXCLASS.ORD;var o=this.childNodes[0];o?this.isEmbellished||o.isKind("mi")?(t=o.setTeXclass(t),this.updateTeXclass(this.core())):(o.setTeXclass(null),t=this):t=this;try{for(var i=s(this.childNodes.slice(1)),a=i.next();!a.done;a=i.next()){var l=a.value;l&&l.setTeXclass(null)}}catch(t){r={error:t}}finally{try{a&&!a.done&&(n=i.return)&&n.call(i)}finally{if(r)throw r.error}}return t},r.defaults=f.defaults,r}(f);e.AbstractMmlBaseNode=y;var O=function(t){function r(){return null!==t&&t.apply(this,arguments)||this}return o(r,t),Object.defineProperty(r.prototype,"isToken",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isEmbellished",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isSpacelike",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"linebreakContainer",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"hasNewLine",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"arity",{get:function(){return 0},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"isInferred",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"notParent",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"Parent",{get:function(){return this.parent},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"texClass",{get:function(){return e.TEXCLASS.NONE},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"prevClass",{get:function(){return e.TEXCLASS.NONE},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"prevLevel",{get:function(){return 0},enumerable:!1,configurable:!0}),r.prototype.hasSpacingAttributes=function(){return!1},Object.defineProperty(r.prototype,"attributes",{get:function(){return null},enumerable:!1,configurable:!0}),r.prototype.core=function(){return this},r.prototype.coreMO=function(){return this},r.prototype.coreIndex=function(){return 0},r.prototype.childPosition=function(){return 0},r.prototype.setTeXclass=function(t){return t},r.prototype.texSpacing=function(){return""},r.prototype.setInheritedAttributes=function(t,e,r,n){},r.prototype.inheritAttributesFrom=function(t){},r.prototype.verifyTree=function(t){},r.prototype.mError=function(t,e,r){void 0===r&&(r=!1)},r}(u.AbstractEmptyNode);e.AbstractMmlEmptyNode=O;var M=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.text="",e}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"text"},enumerable:!1,configurable:!0}),e.prototype.getText=function(){return this.text},e.prototype.setText=function(t){return this.text=t,this},e.prototype.toString=function(){return this.text},e}(O);e.TextNode=M;var E=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.xml=null,e.adaptor=null,e}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"XML"},enumerable:!1,configurable:!0}),e.prototype.getXML=function(){return this.xml},e.prototype.setXML=function(t,e){return void 0===e&&(e=null),this.xml=t,this.adaptor=e,this},e.prototype.getSerializedXML=function(){return this.adaptor.serializeXML(this.xml)},e.prototype.toString=function(){return"XML data"},e}(O);e.XMLNode=E},3948:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;rthis.childNodes.length&&(t=1),this.attributes.set("selection",t)},e.defaults=i(i({},s.AbstractMmlNode.defaults),{actiontype:"toggle",selection:1}),e}(s.AbstractMmlNode);e.MmlMaction=a},142:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMfenced=void 0;var a=r(9007),l=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.texclass=a.TEXCLASS.INNER,e.separators=[],e.open=null,e.close=null,e}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"mfenced"},enumerable:!1,configurable:!0}),e.prototype.setTeXclass=function(t){this.getPrevClass(t),this.open&&(t=this.open.setTeXclass(t)),this.childNodes[0]&&(t=this.childNodes[0].setTeXclass(t));for(var e=1,r=this.childNodes.length;e=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMfrac=void 0;var a=r(9007),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"mfrac"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"arity",{get:function(){return 2},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"linebreakContainer",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.setTeXclass=function(t){var e,r;this.getPrevClass(t);try{for(var n=s(this.childNodes),o=n.next();!o.done;o=n.next()){o.value.setTeXclass(null)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}return this},e.prototype.setChildInheritedAttributes=function(t,e,r,n){(!e||r>0)&&r++,this.childNodes[0].setInheritedAttributes(t,!1,r,n),this.childNodes[1].setInheritedAttributes(t,!1,r,!0)},e.defaults=i(i({},a.AbstractMmlBaseNode.defaults),{linethickness:"medium",numalign:"center",denomalign:"center",bevelled:!1}),e}(a.AbstractMmlBaseNode);e.MmlMfrac=l},3985:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r1&&r.match(e.operatorName)&&"normal"===this.attributes.get("mathvariant")&&void 0===this.getProperty("autoOP")&&void 0===this.getProperty("texClass")&&(this.texClass=s.TEXCLASS.OP,this.setProperty("autoOP",!0)),this},e.defaults=i({},s.AbstractMmlTokenNode.defaults),e.operatorName=/^[a-z][a-z0-9]*$/i,e.singleCharacter=/^[\uD800-\uDBFF]?.[\u0300-\u036F\u1AB0-\u1ABE\u1DC0-\u1DFF\u20D0-\u20EF]*$/,e}(s.AbstractMmlTokenNode);e.MmlMi=a},6405:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},a=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMo=void 0;var l=r(9007),u=r(4082),c=r(505),p=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e._texClass=null,e.lspace=5/18,e.rspace=5/18,e}return o(e,t),Object.defineProperty(e.prototype,"texClass",{get:function(){if(null===this._texClass){var t=this.getText(),e=s(this.handleExplicitForm(this.getForms()),3),r=e[0],n=e[1],o=e[2],i=this.constructor.OPTABLE,a=i[r][t]||i[n][t]||i[o][t];return a?a[2]:l.TEXCLASS.REL}return this._texClass},set:function(t){this._texClass=t},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"kind",{get:function(){return"mo"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isEmbellished",{get:function(){return!0},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"hasNewLine",{get:function(){return"newline"===this.attributes.get("linebreak")},enumerable:!1,configurable:!0}),e.prototype.coreParent=function(){for(var t=this,e=this,r=this.factory.getNodeClass("math");e&&e.isEmbellished&&e.coreMO()===this&&!(e instanceof r);)t=e,e=e.parent;return t},e.prototype.coreText=function(t){if(!t)return"";if(t.isEmbellished)return t.coreMO().getText();for(;((t.isKind("mrow")||t.isKind("TeXAtom")||t.isKind("mstyle")||t.isKind("mphantom"))&&1===t.childNodes.length||t.isKind("munderover"))&&t.childNodes[0];)t=t.childNodes[0];return t.isToken?t.getText():""},e.prototype.hasSpacingAttributes=function(){return this.attributes.isSet("lspace")||this.attributes.isSet("rspace")},Object.defineProperty(e.prototype,"isAccent",{get:function(){var t=!1,e=this.coreParent().parent;if(e){var r=e.isKind("mover")?e.childNodes[e.over].coreMO()?"accent":"":e.isKind("munder")?e.childNodes[e.under].coreMO()?"accentunder":"":e.isKind("munderover")?this===e.childNodes[e.over].coreMO()?"accent":this===e.childNodes[e.under].coreMO()?"accentunder":"":"";if(r)t=void 0!==e.attributes.getExplicit(r)?t:this.attributes.get("accent")}return t},enumerable:!1,configurable:!0}),e.prototype.setTeXclass=function(t){var e=this.attributes.getList("form","fence"),r=e.form,n=e.fence;return void 0===this.getProperty("texClass")&&(this.attributes.isSet("lspace")||this.attributes.isSet("rspace"))?null:(n&&this.texClass===l.TEXCLASS.REL&&("prefix"===r&&(this.texClass=l.TEXCLASS.OPEN),"postfix"===r&&(this.texClass=l.TEXCLASS.CLOSE)),"\u2061"===this.getText()?(t&&void 0===t.getProperty("texClass")&&"italic"!==t.attributes.get("mathvariant")&&(t.texClass=l.TEXCLASS.OP,t.setProperty("fnOP",!0)),this.texClass=this.prevClass=l.TEXCLASS.NONE,t):this.adjustTeXclass(t))},e.prototype.adjustTeXclass=function(t){var e=this.texClass,r=this.prevClass;if(e===l.TEXCLASS.NONE)return t;if(t?(!t.getProperty("autoOP")||e!==l.TEXCLASS.BIN&&e!==l.TEXCLASS.REL||(r=t.texClass=l.TEXCLASS.ORD),r=this.prevClass=t.texClass||l.TEXCLASS.ORD,this.prevLevel=this.attributes.getInherited("scriptlevel")):r=this.prevClass=l.TEXCLASS.NONE,e!==l.TEXCLASS.BIN||r!==l.TEXCLASS.NONE&&r!==l.TEXCLASS.BIN&&r!==l.TEXCLASS.OP&&r!==l.TEXCLASS.REL&&r!==l.TEXCLASS.OPEN&&r!==l.TEXCLASS.PUNCT)if(r!==l.TEXCLASS.BIN||e!==l.TEXCLASS.REL&&e!==l.TEXCLASS.CLOSE&&e!==l.TEXCLASS.PUNCT){if(e===l.TEXCLASS.BIN){for(var n=this,o=this.parent;o&&o.parent&&o.isEmbellished&&(1===o.childNodes.length||!o.isKind("mrow")&&o.core()===n);)n=o,o=o.parent;o.childNodes[o.childNodes.length-1]===n&&(this.texClass=l.TEXCLASS.ORD)}}else t.texClass=this.prevClass=l.TEXCLASS.ORD;else this.texClass=l.TEXCLASS.ORD;return this},e.prototype.setInheritedAttributes=function(e,r,n,o){void 0===e&&(e={}),void 0===r&&(r=!1),void 0===n&&(n=0),void 0===o&&(o=!1),t.prototype.setInheritedAttributes.call(this,e,r,n,o);var i=this.getText();this.checkOperatorTable(i),this.checkPseudoScripts(i),this.checkPrimes(i),this.checkMathAccent(i)},e.prototype.checkOperatorTable=function(t){var e,r,n=s(this.handleExplicitForm(this.getForms()),3),o=n[0],i=n[1],l=n[2];this.attributes.setInherited("form",o);var u=this.constructor.OPTABLE,c=u[o][t]||u[i][t]||u[l][t];if(c){void 0===this.getProperty("texClass")&&(this.texClass=c[2]);try{for(var p=a(Object.keys(c[3]||{})),f=p.next();!f.done;f=p.next()){var h=f.value;this.attributes.setInherited(h,c[3][h])}}catch(t){e={error:t}}finally{try{f&&!f.done&&(r=p.return)&&r.call(p)}finally{if(e)throw e.error}}this.lspace=(c[0]+1)/18,this.rspace=(c[1]+1)/18}else{var d=this.getRange(t);if(d){void 0===this.getProperty("texClass")&&(this.texClass=d[2]);var y=this.constructor.MMLSPACING[d[2]];this.lspace=(y[0]+1)/18,this.rspace=(y[1]+1)/18}}},e.prototype.getForms=function(){for(var t=this,e=this.parent,r=this.Parent;r&&r.isEmbellished;)t=e,e=r.parent,r=r.Parent;if(e&&e.isKind("mrow")&&1!==e.nonSpaceLength()){if(e.firstNonSpace()===t)return["prefix","infix","postfix"];if(e.lastNonSpace()===t)return["postfix","infix","prefix"]}return["infix","prefix","postfix"]},e.prototype.handleExplicitForm=function(t){if(this.attributes.isSet("form")){var e=this.attributes.get("form");t=[e].concat(t.filter((function(t){return t!==e})))}return t},e.prototype.getRange=function(t){var e,r;if(!t.match(/^[\uD800-\uDBFF]?.$/))return null;var n=t.codePointAt(0),o=this.constructor.RANGES;try{for(var i=a(o),s=i.next();!s.done;s=i.next()){var l=s.value;if(l[0]<=n&&n<=l[1])return l;if(n=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MmlInferredMrow=e.MmlMrow=void 0;var a=r(9007),l=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e._core=null,e}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"mrow"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isSpacelike",{get:function(){var t,e;try{for(var r=s(this.childNodes),n=r.next();!n.done;n=r.next()){if(!n.value.isSpacelike)return!1}}catch(e){t={error:e}}finally{try{n&&!n.done&&(e=r.return)&&e.call(r)}finally{if(t)throw t.error}}return!0},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isEmbellished",{get:function(){var t,e,r=!1,n=0;try{for(var o=s(this.childNodes),i=o.next();!i.done;i=o.next()){var a=i.value;if(a)if(a.isEmbellished){if(r)return!1;r=!0,this._core=n}else if(!a.isSpacelike)return!1;n++}}catch(e){t={error:e}}finally{try{i&&!i.done&&(e=o.return)&&e.call(o)}finally{if(t)throw t.error}}return r},enumerable:!1,configurable:!0}),e.prototype.core=function(){return this.isEmbellished&&null!=this._core?this.childNodes[this._core]:this},e.prototype.coreMO=function(){return this.isEmbellished&&null!=this._core?this.childNodes[this._core].coreMO():this},e.prototype.nonSpaceLength=function(){var t,e,r=0;try{for(var n=s(this.childNodes),o=n.next();!o.done;o=n.next()){var i=o.value;i&&!i.isSpacelike&&r++}}catch(e){t={error:e}}finally{try{o&&!o.done&&(e=n.return)&&e.call(n)}finally{if(t)throw t.error}}return r},e.prototype.firstNonSpace=function(){var t,e;try{for(var r=s(this.childNodes),n=r.next();!n.done;n=r.next()){var o=n.value;if(o&&!o.isSpacelike)return o}}catch(e){t={error:e}}finally{try{n&&!n.done&&(e=r.return)&&e.call(r)}finally{if(t)throw t.error}}return null},e.prototype.lastNonSpace=function(){for(var t=this.childNodes.length;--t>=0;){var e=this.childNodes[t];if(e&&!e.isSpacelike)return e}return null},e.prototype.setTeXclass=function(t){var e,r,n,o;if(null!=this.getProperty("open")||null!=this.getProperty("close")){this.getPrevClass(t),t=null;try{for(var i=s(this.childNodes),l=i.next();!l.done;l=i.next()){t=l.value.setTeXclass(t)}}catch(t){e={error:t}}finally{try{l&&!l.done&&(r=i.return)&&r.call(i)}finally{if(e)throw e.error}}null==this.texClass&&(this.texClass=a.TEXCLASS.INNER)}else{try{for(var u=s(this.childNodes),c=u.next();!c.done;c=u.next()){t=c.value.setTeXclass(t)}}catch(t){n={error:t}}finally{try{c&&!c.done&&(o=u.return)&&o.call(u)}finally{if(n)throw n.error}}this.childNodes[0]&&this.updateTeXclass(this.childNodes[0])}return t},e.defaults=i({},a.AbstractMmlNode.defaults),e}(a.AbstractMmlNode);e.MmlMrow=l;var u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"inferredMrow"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isInferred",{get:function(){return!0},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"notParent",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.toString=function(){return"["+this.childNodes.join(",")+"]"},e.defaults=l.defaults,e}(l);e.MmlInferredMrow=u},7265:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMtable=void 0;var a=r(9007),l=r(505),u=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.properties={useHeight:!0},e.texclass=a.TEXCLASS.ORD,e}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"mtable"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"linebreakContainer",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.setInheritedAttributes=function(e,r,n,o){var i,l;try{for(var u=s(a.indentAttributes),c=u.next();!c.done;c=u.next()){var p=c.value;e[p]&&this.attributes.setInherited(p,e[p][1]),void 0!==this.attributes.getExplicit(p)&&delete this.attributes.getAllAttributes()[p]}}catch(t){i={error:t}}finally{try{c&&!c.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}t.prototype.setInheritedAttributes.call(this,e,r,n,o)},e.prototype.setChildInheritedAttributes=function(t,e,r,n){var o,i,a,u;try{for(var c=s(this.childNodes),p=c.next();!p.done;p=c.next()){(y=p.value).isKind("mtr")||this.replaceChild(this.factory.create("mtr"),y).appendChild(y)}}catch(t){o={error:t}}finally{try{p&&!p.done&&(i=c.return)&&i.call(c)}finally{if(o)throw o.error}}r=this.getProperty("scriptlevel")||r,e=!(!this.attributes.getExplicit("displaystyle")&&!this.attributes.getDefault("displaystyle")),t=this.addInheritedAttributes(t,{columnalign:this.attributes.get("columnalign"),rowalign:"center"});var f=l.split(this.attributes.get("rowalign"));try{for(var h=s(this.childNodes),d=h.next();!d.done;d=h.next()){var y=d.value;t.rowalign[1]=f.shift()||t.rowalign[1],y.setInheritedAttributes(t,e,r,n)}}catch(t){a={error:t}}finally{try{d&&!d.done&&(u=h.return)&&u.call(h)}finally{if(a)throw a.error}}},e.prototype.verifyChildren=function(e){var r,n;if(!e.fixMtables)try{for(var o=s(this.childNodes),i=o.next();!i.done;i=o.next()){i.value.isKind("mtr")||this.mError("Children of "+this.kind+" must be mtr or mlabeledtr",e)}}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}t.prototype.verifyChildren.call(this,e)},e.prototype.setTeXclass=function(t){var e,r;this.getPrevClass(t);try{for(var n=s(this.childNodes),o=n.next();!o.done;o=n.next()){o.value.setTeXclass(null)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}return this},e.defaults=i(i({},a.AbstractMmlNode.defaults),{align:"axis",rowalign:"baseline",columnalign:"center",groupalign:"{left}",alignmentscope:!0,columnwidth:"auto",width:"auto",rowspacing:"1ex",columnspacing:".8em",rowlines:"none",columnlines:"none",frame:"none",framespacing:"0.4em 0.5ex",equalrows:!1,equalcolumns:!1,displaystyle:!1,side:"right",minlabelspacing:"0.8em"}),e}(a.AbstractMmlNode);e.MmlMtable=u},4359:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMlabeledtr=e.MmlMtr=void 0;var a=r(9007),l=r(91),u=r(505),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"mtr"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"linebreakContainer",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.setChildInheritedAttributes=function(t,e,r,n){var o,i,a,l;try{for(var c=s(this.childNodes),p=c.next();!p.done;p=c.next()){(y=p.value).isKind("mtd")||this.replaceChild(this.factory.create("mtd"),y).appendChild(y)}}catch(t){o={error:t}}finally{try{p&&!p.done&&(i=c.return)&&i.call(c)}finally{if(o)throw o.error}}var f=u.split(this.attributes.get("columnalign"));1===this.arity&&f.unshift(this.parent.attributes.get("side")),t=this.addInheritedAttributes(t,{rowalign:this.attributes.get("rowalign"),columnalign:"center"});try{for(var h=s(this.childNodes),d=h.next();!d.done;d=h.next()){var y=d.value;t.columnalign[1]=f.shift()||t.columnalign[1],y.setInheritedAttributes(t,e,r,n)}}catch(t){a={error:t}}finally{try{d&&!d.done&&(l=h.return)&&l.call(h)}finally{if(a)throw a.error}}},e.prototype.verifyChildren=function(e){var r,n;if(!this.parent||this.parent.isKind("mtable")){if(!e.fixMtables)try{for(var o=s(this.childNodes),i=o.next();!i.done;i=o.next()){var a=i.value;if(!a.isKind("mtd"))this.replaceChild(this.factory.create("mtr"),a).mError("Children of "+this.kind+" must be mtd",e,!0)}}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}t.prototype.verifyChildren.call(this,e)}else this.mError(this.kind+" can only be a child of an mtable",e,!0)},e.prototype.setTeXclass=function(t){var e,r;this.getPrevClass(t);try{for(var n=s(this.childNodes),o=n.next();!o.done;o=n.next()){o.value.setTeXclass(null)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}return this},e.defaults=i(i({},a.AbstractMmlNode.defaults),{rowalign:l.INHERIT,columnalign:l.INHERIT,groupalign:l.INHERIT}),e}(a.AbstractMmlNode);e.MmlMtr=c;var p=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"mlabeledtr"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"arity",{get:function(){return 1},enumerable:!1,configurable:!0}),e}(c);e.MmlMlabeledtr=p},5184:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,n=arguments.length;r":e.MO.BIN5,".":[0,3,n.TEXCLASS.PUNCT,{separator:!0}],"/":e.MO.ORD11,"//":o(1,1),"/=":e.MO.BIN4,":":[1,2,n.TEXCLASS.REL,null],":=":e.MO.BIN4,";":[0,3,n.TEXCLASS.PUNCT,{linebreakstyle:"after",separator:!0}],"<":e.MO.REL,"<=":e.MO.BIN5,"<>":o(1,1),"=":e.MO.REL,"==":e.MO.BIN4,">":e.MO.REL,">=":e.MO.BIN5,"?":[1,1,n.TEXCLASS.CLOSE,null],"@":e.MO.ORD11,"\\":e.MO.ORD,"^":e.MO.ORD11,_:e.MO.ORD11,"|":[2,2,n.TEXCLASS.ORD,{fence:!0,stretchy:!0,symmetric:!0}],"||":[2,2,n.TEXCLASS.BIN,{fence:!0,stretchy:!0,symmetric:!0}],"|||":[2,2,n.TEXCLASS.ORD,{fence:!0,stretchy:!0,symmetric:!0}],"\xb1":e.MO.BIN4,"\xb7":e.MO.BIN4,"\xd7":e.MO.BIN4,"\xf7":e.MO.BIN4,"\u02b9":e.MO.ORD,"\u0300":e.MO.ACCENT,"\u0301":e.MO.ACCENT,"\u0303":e.MO.WIDEACCENT,"\u0304":e.MO.ACCENT,"\u0306":e.MO.ACCENT,"\u0307":e.MO.ACCENT,"\u0308":e.MO.ACCENT,"\u030c":e.MO.ACCENT,"\u0332":e.MO.WIDEACCENT,"\u0338":e.MO.REL4,"\u2015":[0,0,n.TEXCLASS.ORD,{stretchy:!0}],"\u2017":[0,0,n.TEXCLASS.ORD,{stretchy:!0}],"\u2020":e.MO.BIN3,"\u2021":e.MO.BIN3,"\u2022":e.MO.BIN4,"\u2026":e.MO.INNER,"\u2043":e.MO.BIN4,"\u2044":e.MO.TALLBIN,"\u2061":e.MO.ORD,"\u2062":e.MO.ORD,"\u2063":[0,0,n.TEXCLASS.ORD,{linebreakstyle:"after",separator:!0}],"\u2064":e.MO.ORD,"\u20d7":e.MO.ACCENT,"\u2111":e.MO.ORD,"\u2113":e.MO.ORD,"\u2118":e.MO.ORD,"\u211c":e.MO.ORD,"\u2190":e.MO.WIDEREL,"\u2191":e.MO.RELSTRETCH,"\u2192":e.MO.WIDEREL,"\u2193":e.MO.RELSTRETCH,"\u2194":e.MO.WIDEREL,"\u2195":e.MO.RELSTRETCH,"\u2196":e.MO.RELSTRETCH,"\u2197":e.MO.RELSTRETCH,"\u2198":e.MO.RELSTRETCH,"\u2199":e.MO.RELSTRETCH,"\u219a":e.MO.RELACCENT,"\u219b":e.MO.RELACCENT,"\u219c":e.MO.WIDEREL,"\u219d":e.MO.WIDEREL,"\u219e":e.MO.WIDEREL,"\u219f":e.MO.WIDEREL,"\u21a0":e.MO.WIDEREL,"\u21a1":e.MO.RELSTRETCH,"\u21a2":e.MO.WIDEREL,"\u21a3":e.MO.WIDEREL,"\u21a4":e.MO.WIDEREL,"\u21a5":e.MO.RELSTRETCH,"\u21a6":e.MO.WIDEREL,"\u21a7":e.MO.RELSTRETCH,"\u21a8":e.MO.RELSTRETCH,"\u21a9":e.MO.WIDEREL,"\u21aa":e.MO.WIDEREL,"\u21ab":e.MO.WIDEREL,"\u21ac":e.MO.WIDEREL,"\u21ad":e.MO.WIDEREL,"\u21ae":e.MO.RELACCENT,"\u21af":e.MO.RELSTRETCH,"\u21b0":e.MO.RELSTRETCH,"\u21b1":e.MO.RELSTRETCH,"\u21b2":e.MO.RELSTRETCH,"\u21b3":e.MO.RELSTRETCH,"\u21b4":e.MO.RELSTRETCH,"\u21b5":e.MO.RELSTRETCH,"\u21b6":e.MO.RELACCENT,"\u21b7":e.MO.RELACCENT,"\u21b8":e.MO.REL,"\u21b9":e.MO.WIDEREL,"\u21ba":e.MO.REL,"\u21bb":e.MO.REL,"\u21bc":e.MO.WIDEREL,"\u21bd":e.MO.WIDEREL,"\u21be":e.MO.RELSTRETCH,"\u21bf":e.MO.RELSTRETCH,"\u21c0":e.MO.WIDEREL,"\u21c1":e.MO.WIDEREL,"\u21c2":e.MO.RELSTRETCH,"\u21c3":e.MO.RELSTRETCH,"\u21c4":e.MO.WIDEREL,"\u21c5":e.MO.RELSTRETCH,"\u21c6":e.MO.WIDEREL,"\u21c7":e.MO.WIDEREL,"\u21c8":e.MO.RELSTRETCH,"\u21c9":e.MO.WIDEREL,"\u21ca":e.MO.RELSTRETCH,"\u21cb":e.MO.WIDEREL,"\u21cc":e.MO.WIDEREL,"\u21cd":e.MO.RELACCENT,"\u21ce":e.MO.RELACCENT,"\u21cf":e.MO.RELACCENT,"\u21d0":e.MO.WIDEREL,"\u21d1":e.MO.RELSTRETCH,"\u21d2":e.MO.WIDEREL,"\u21d3":e.MO.RELSTRETCH,"\u21d4":e.MO.WIDEREL,"\u21d5":e.MO.RELSTRETCH,"\u21d6":e.MO.RELSTRETCH,"\u21d7":e.MO.RELSTRETCH,"\u21d8":e.MO.RELSTRETCH,"\u21d9":e.MO.RELSTRETCH,"\u21da":e.MO.WIDEREL,"\u21db":e.MO.WIDEREL,"\u21dc":e.MO.WIDEREL,"\u21dd":e.MO.WIDEREL,"\u21de":e.MO.REL,"\u21df":e.MO.REL,"\u21e0":e.MO.WIDEREL,"\u21e1":e.MO.RELSTRETCH,"\u21e2":e.MO.WIDEREL,"\u21e3":e.MO.RELSTRETCH,"\u21e4":e.MO.WIDEREL,"\u21e5":e.MO.WIDEREL,"\u21e6":e.MO.WIDEREL,"\u21e7":e.MO.RELSTRETCH,"\u21e8":e.MO.WIDEREL,"\u21e9":e.MO.RELSTRETCH,"\u21ea":e.MO.RELSTRETCH,"\u21eb":e.MO.RELSTRETCH,"\u21ec":e.MO.RELSTRETCH,"\u21ed":e.MO.RELSTRETCH,"\u21ee":e.MO.RELSTRETCH,"\u21ef":e.MO.RELSTRETCH,"\u21f0":e.MO.WIDEREL,"\u21f1":e.MO.REL,"\u21f2":e.MO.REL,"\u21f3":e.MO.RELSTRETCH,"\u21f4":e.MO.RELACCENT,"\u21f5":e.MO.RELSTRETCH,"\u21f6":e.MO.WIDEREL,"\u21f7":e.MO.RELACCENT,"\u21f8":e.MO.RELACCENT,"\u21f9":e.MO.RELACCENT,"\u21fa":e.MO.RELACCENT,"\u21fb":e.MO.RELACCENT,"\u21fc":e.MO.RELACCENT,"\u21fd":e.MO.WIDEREL,"\u21fe":e.MO.WIDEREL,"\u21ff":e.MO.WIDEREL,"\u2201":o(1,2,n.TEXCLASS.ORD),"\u2205":e.MO.ORD,"\u2206":e.MO.BIN3,"\u2208":e.MO.REL,"\u2209":e.MO.REL,"\u220a":e.MO.REL,"\u220b":e.MO.REL,"\u220c":e.MO.REL,"\u220d":e.MO.REL,"\u220e":e.MO.BIN3,"\u2212":e.MO.BIN4,"\u2213":e.MO.BIN4,"\u2214":e.MO.BIN4,"\u2215":e.MO.TALLBIN,"\u2216":e.MO.BIN4,"\u2217":e.MO.BIN4,"\u2218":e.MO.BIN4,"\u2219":e.MO.BIN4,"\u221d":e.MO.REL,"\u221e":e.MO.ORD,"\u221f":e.MO.REL,"\u2223":e.MO.REL,"\u2224":e.MO.REL,"\u2225":e.MO.REL,"\u2226":e.MO.REL,"\u2227":e.MO.BIN4,"\u2228":e.MO.BIN4,"\u2229":e.MO.BIN4,"\u222a":e.MO.BIN4,"\u2234":e.MO.REL,"\u2235":e.MO.REL,"\u2236":e.MO.REL,"\u2237":e.MO.REL,"\u2238":e.MO.BIN4,"\u2239":e.MO.REL,"\u223a":e.MO.BIN4,"\u223b":e.MO.REL,"\u223c":e.MO.REL,"\u223d":e.MO.REL,"\u223d\u0331":e.MO.BIN3,"\u223e":e.MO.REL,"\u223f":e.MO.BIN3,"\u2240":e.MO.BIN4,"\u2241":e.MO.REL,"\u2242":e.MO.REL,"\u2242\u0338":e.MO.REL,"\u2243":e.MO.REL,"\u2244":e.MO.REL,"\u2245":e.MO.REL,"\u2246":e.MO.REL,"\u2247":e.MO.REL,"\u2248":e.MO.REL,"\u2249":e.MO.REL,"\u224a":e.MO.REL,"\u224b":e.MO.REL,"\u224c":e.MO.REL,"\u224d":e.MO.REL,"\u224e":e.MO.REL,"\u224e\u0338":e.MO.REL,"\u224f":e.MO.REL,"\u224f\u0338":e.MO.REL,"\u2250":e.MO.REL,"\u2251":e.MO.REL,"\u2252":e.MO.REL,"\u2253":e.MO.REL,"\u2254":e.MO.REL,"\u2255":e.MO.REL,"\u2256":e.MO.REL,"\u2257":e.MO.REL,"\u2258":e.MO.REL,"\u2259":e.MO.REL,"\u225a":e.MO.REL,"\u225b":e.MO.REL,"\u225c":e.MO.REL,"\u225d":e.MO.REL,"\u225e":e.MO.REL,"\u225f":e.MO.REL,"\u2260":e.MO.REL,"\u2261":e.MO.REL,"\u2262":e.MO.REL,"\u2263":e.MO.REL,"\u2264":e.MO.REL,"\u2265":e.MO.REL,"\u2266":e.MO.REL,"\u2266\u0338":e.MO.REL,"\u2267":e.MO.REL,"\u2268":e.MO.REL,"\u2269":e.MO.REL,"\u226a":e.MO.REL,"\u226a\u0338":e.MO.REL,"\u226b":e.MO.REL,"\u226b\u0338":e.MO.REL,"\u226c":e.MO.REL,"\u226d":e.MO.REL,"\u226e":e.MO.REL,"\u226f":e.MO.REL,"\u2270":e.MO.REL,"\u2271":e.MO.REL,"\u2272":e.MO.REL,"\u2273":e.MO.REL,"\u2274":e.MO.REL,"\u2275":e.MO.REL,"\u2276":e.MO.REL,"\u2277":e.MO.REL,"\u2278":e.MO.REL,"\u2279":e.MO.REL,"\u227a":e.MO.REL,"\u227b":e.MO.REL,"\u227c":e.MO.REL,"\u227d":e.MO.REL,"\u227e":e.MO.REL,"\u227f":e.MO.REL,"\u227f\u0338":e.MO.REL,"\u2280":e.MO.REL,"\u2281":e.MO.REL,"\u2282":e.MO.REL,"\u2282\u20d2":e.MO.REL,"\u2283":e.MO.REL,"\u2283\u20d2":e.MO.REL,"\u2284":e.MO.REL,"\u2285":e.MO.REL,"\u2286":e.MO.REL,"\u2287":e.MO.REL,"\u2288":e.MO.REL,"\u2289":e.MO.REL,"\u228a":e.MO.REL,"\u228b":e.MO.REL,"\u228c":e.MO.BIN4,"\u228d":e.MO.BIN4,"\u228e":e.MO.BIN4,"\u228f":e.MO.REL,"\u228f\u0338":e.MO.REL,"\u2290":e.MO.REL,"\u2290\u0338":e.MO.REL,"\u2291":e.MO.REL,"\u2292":e.MO.REL,"\u2293":e.MO.BIN4,"\u2294":e.MO.BIN4,"\u2295":e.MO.BIN4,"\u2296":e.MO.BIN4,"\u2297":e.MO.BIN4,"\u2298":e.MO.BIN4,"\u2299":e.MO.BIN4,"\u229a":e.MO.BIN4,"\u229b":e.MO.BIN4,"\u229c":e.MO.BIN4,"\u229d":e.MO.BIN4,"\u229e":e.MO.BIN4,"\u229f":e.MO.BIN4,"\u22a0":e.MO.BIN4,"\u22a1":e.MO.BIN4,"\u22a2":e.MO.REL,"\u22a3":e.MO.REL,"\u22a4":e.MO.ORD55,"\u22a5":e.MO.REL,"\u22a6":e.MO.REL,"\u22a7":e.MO.REL,"\u22a8":e.MO.REL,"\u22a9":e.MO.REL,"\u22aa":e.MO.REL,"\u22ab":e.MO.REL,"\u22ac":e.MO.REL,"\u22ad":e.MO.REL,"\u22ae":e.MO.REL,"\u22af":e.MO.REL,"\u22b0":e.MO.REL,"\u22b1":e.MO.REL,"\u22b2":e.MO.REL,"\u22b3":e.MO.REL,"\u22b4":e.MO.REL,"\u22b5":e.MO.REL,"\u22b6":e.MO.REL,"\u22b7":e.MO.REL,"\u22b8":e.MO.REL,"\u22b9":e.MO.REL,"\u22ba":e.MO.BIN4,"\u22bb":e.MO.BIN4,"\u22bc":e.MO.BIN4,"\u22bd":e.MO.BIN4,"\u22be":e.MO.BIN3,"\u22bf":e.MO.BIN3,"\u22c4":e.MO.BIN4,"\u22c5":e.MO.BIN4,"\u22c6":e.MO.BIN4,"\u22c7":e.MO.BIN4,"\u22c8":e.MO.REL,"\u22c9":e.MO.BIN4,"\u22ca":e.MO.BIN4,"\u22cb":e.MO.BIN4,"\u22cc":e.MO.BIN4,"\u22cd":e.MO.REL,"\u22ce":e.MO.BIN4,"\u22cf":e.MO.BIN4,"\u22d0":e.MO.REL,"\u22d1":e.MO.REL,"\u22d2":e.MO.BIN4,"\u22d3":e.MO.BIN4,"\u22d4":e.MO.REL,"\u22d5":e.MO.REL,"\u22d6":e.MO.REL,"\u22d7":e.MO.REL,"\u22d8":e.MO.REL,"\u22d9":e.MO.REL,"\u22da":e.MO.REL,"\u22db":e.MO.REL,"\u22dc":e.MO.REL,"\u22dd":e.MO.REL,"\u22de":e.MO.REL,"\u22df":e.MO.REL,"\u22e0":e.MO.REL,"\u22e1":e.MO.REL,"\u22e2":e.MO.REL,"\u22e3":e.MO.REL,"\u22e4":e.MO.REL,"\u22e5":e.MO.REL,"\u22e6":e.MO.REL,"\u22e7":e.MO.REL,"\u22e8":e.MO.REL,"\u22e9":e.MO.REL,"\u22ea":e.MO.REL,"\u22eb":e.MO.REL,"\u22ec":e.MO.REL,"\u22ed":e.MO.REL,"\u22ee":e.MO.ORD55,"\u22ef":e.MO.INNER,"\u22f0":e.MO.REL,"\u22f1":[5,5,n.TEXCLASS.INNER,null],"\u22f2":e.MO.REL,"\u22f3":e.MO.REL,"\u22f4":e.MO.REL,"\u22f5":e.MO.REL,"\u22f6":e.MO.REL,"\u22f7":e.MO.REL,"\u22f8":e.MO.REL,"\u22f9":e.MO.REL,"\u22fa":e.MO.REL,"\u22fb":e.MO.REL,"\u22fc":e.MO.REL,"\u22fd":e.MO.REL,"\u22fe":e.MO.REL,"\u22ff":e.MO.REL,"\u2305":e.MO.BIN3,"\u2306":e.MO.BIN3,"\u2322":e.MO.REL4,"\u2323":e.MO.REL4,"\u2329":e.MO.OPEN,"\u232a":e.MO.CLOSE,"\u23aa":e.MO.ORD,"\u23af":[0,0,n.TEXCLASS.ORD,{stretchy:!0}],"\u23b0":e.MO.OPEN,"\u23b1":e.MO.CLOSE,"\u2500":e.MO.ORD,"\u25b3":e.MO.BIN4,"\u25b5":e.MO.BIN4,"\u25b9":e.MO.BIN4,"\u25bd":e.MO.BIN4,"\u25bf":e.MO.BIN4,"\u25c3":e.MO.BIN4,"\u25ef":e.MO.BIN3,"\u2660":e.MO.ORD,"\u2661":e.MO.ORD,"\u2662":e.MO.ORD,"\u2663":e.MO.ORD,"\u2758":e.MO.REL,"\u27f0":e.MO.RELSTRETCH,"\u27f1":e.MO.RELSTRETCH,"\u27f5":e.MO.WIDEREL,"\u27f6":e.MO.WIDEREL,"\u27f7":e.MO.WIDEREL,"\u27f8":e.MO.WIDEREL,"\u27f9":e.MO.WIDEREL,"\u27fa":e.MO.WIDEREL,"\u27fb":e.MO.WIDEREL,"\u27fc":e.MO.WIDEREL,"\u27fd":e.MO.WIDEREL,"\u27fe":e.MO.WIDEREL,"\u27ff":e.MO.WIDEREL,"\u2900":e.MO.RELACCENT,"\u2901":e.MO.RELACCENT,"\u2902":e.MO.RELACCENT,"\u2903":e.MO.RELACCENT,"\u2904":e.MO.RELACCENT,"\u2905":e.MO.RELACCENT,"\u2906":e.MO.RELACCENT,"\u2907":e.MO.RELACCENT,"\u2908":e.MO.REL,"\u2909":e.MO.REL,"\u290a":e.MO.RELSTRETCH,"\u290b":e.MO.RELSTRETCH,"\u290c":e.MO.WIDEREL,"\u290d":e.MO.WIDEREL,"\u290e":e.MO.WIDEREL,"\u290f":e.MO.WIDEREL,"\u2910":e.MO.WIDEREL,"\u2911":e.MO.RELACCENT,"\u2912":e.MO.RELSTRETCH,"\u2913":e.MO.RELSTRETCH,"\u2914":e.MO.RELACCENT,"\u2915":e.MO.RELACCENT,"\u2916":e.MO.RELACCENT,"\u2917":e.MO.RELACCENT,"\u2918":e.MO.RELACCENT,"\u2919":e.MO.RELACCENT,"\u291a":e.MO.RELACCENT,"\u291b":e.MO.RELACCENT,"\u291c":e.MO.RELACCENT,"\u291d":e.MO.RELACCENT,"\u291e":e.MO.RELACCENT,"\u291f":e.MO.RELACCENT,"\u2920":e.MO.RELACCENT,"\u2921":e.MO.RELSTRETCH,"\u2922":e.MO.RELSTRETCH,"\u2923":e.MO.REL,"\u2924":e.MO.REL,"\u2925":e.MO.REL,"\u2926":e.MO.REL,"\u2927":e.MO.REL,"\u2928":e.MO.REL,"\u2929":e.MO.REL,"\u292a":e.MO.REL,"\u292b":e.MO.REL,"\u292c":e.MO.REL,"\u292d":e.MO.REL,"\u292e":e.MO.REL,"\u292f":e.MO.REL,"\u2930":e.MO.REL,"\u2931":e.MO.REL,"\u2932":e.MO.REL,"\u2933":e.MO.RELACCENT,"\u2934":e.MO.REL,"\u2935":e.MO.REL,"\u2936":e.MO.REL,"\u2937":e.MO.REL,"\u2938":e.MO.REL,"\u2939":e.MO.REL,"\u293a":e.MO.RELACCENT,"\u293b":e.MO.RELACCENT,"\u293c":e.MO.RELACCENT,"\u293d":e.MO.RELACCENT,"\u293e":e.MO.REL,"\u293f":e.MO.REL,"\u2940":e.MO.REL,"\u2941":e.MO.REL,"\u2942":e.MO.RELACCENT,"\u2943":e.MO.RELACCENT,"\u2944":e.MO.RELACCENT,"\u2945":e.MO.RELACCENT,"\u2946":e.MO.RELACCENT,"\u2947":e.MO.RELACCENT,"\u2948":e.MO.RELACCENT,"\u2949":e.MO.REL,"\u294a":e.MO.RELACCENT,"\u294b":e.MO.RELACCENT,"\u294c":e.MO.REL,"\u294d":e.MO.REL,"\u294e":e.MO.WIDEREL,"\u294f":e.MO.RELSTRETCH,"\u2950":e.MO.WIDEREL,"\u2951":e.MO.RELSTRETCH,"\u2952":e.MO.WIDEREL,"\u2953":e.MO.WIDEREL,"\u2954":e.MO.RELSTRETCH,"\u2955":e.MO.RELSTRETCH,"\u2956":e.MO.RELSTRETCH,"\u2957":e.MO.RELSTRETCH,"\u2958":e.MO.RELSTRETCH,"\u2959":e.MO.RELSTRETCH,"\u295a":e.MO.WIDEREL,"\u295b":e.MO.WIDEREL,"\u295c":e.MO.RELSTRETCH,"\u295d":e.MO.RELSTRETCH,"\u295e":e.MO.WIDEREL,"\u295f":e.MO.WIDEREL,"\u2960":e.MO.RELSTRETCH,"\u2961":e.MO.RELSTRETCH,"\u2962":e.MO.RELACCENT,"\u2963":e.MO.REL,"\u2964":e.MO.RELACCENT,"\u2965":e.MO.REL,"\u2966":e.MO.RELACCENT,"\u2967":e.MO.RELACCENT,"\u2968":e.MO.RELACCENT,"\u2969":e.MO.RELACCENT,"\u296a":e.MO.RELACCENT,"\u296b":e.MO.RELACCENT,"\u296c":e.MO.RELACCENT,"\u296d":e.MO.RELACCENT,"\u296e":e.MO.RELSTRETCH,"\u296f":e.MO.RELSTRETCH,"\u2970":e.MO.RELACCENT,"\u2971":e.MO.RELACCENT,"\u2972":e.MO.RELACCENT,"\u2973":e.MO.RELACCENT,"\u2974":e.MO.RELACCENT,"\u2975":e.MO.RELACCENT,"\u2976":e.MO.RELACCENT,"\u2977":e.MO.RELACCENT,"\u2978":e.MO.RELACCENT,"\u2979":e.MO.RELACCENT,"\u297a":e.MO.RELACCENT,"\u297b":e.MO.RELACCENT,"\u297c":e.MO.RELACCENT,"\u297d":e.MO.RELACCENT,"\u297e":e.MO.REL,"\u297f":e.MO.REL,"\u2981":e.MO.BIN3,"\u2982":e.MO.BIN3,"\u2999":e.MO.BIN3,"\u299a":e.MO.BIN3,"\u299b":e.MO.BIN3,"\u299c":e.MO.BIN3,"\u299d":e.MO.BIN3,"\u299e":e.MO.BIN3,"\u299f":e.MO.BIN3,"\u29a0":e.MO.BIN3,"\u29a1":e.MO.BIN3,"\u29a2":e.MO.BIN3,"\u29a3":e.MO.BIN3,"\u29a4":e.MO.BIN3,"\u29a5":e.MO.BIN3,"\u29a6":e.MO.BIN3,"\u29a7":e.MO.BIN3,"\u29a8":e.MO.BIN3,"\u29a9":e.MO.BIN3,"\u29aa":e.MO.BIN3,"\u29ab":e.MO.BIN3,"\u29ac":e.MO.BIN3,"\u29ad":e.MO.BIN3,"\u29ae":e.MO.BIN3,"\u29af":e.MO.BIN3,"\u29b0":e.MO.BIN3,"\u29b1":e.MO.BIN3,"\u29b2":e.MO.BIN3,"\u29b3":e.MO.BIN3,"\u29b4":e.MO.BIN3,"\u29b5":e.MO.BIN3,"\u29b6":e.MO.BIN4,"\u29b7":e.MO.BIN4,"\u29b8":e.MO.BIN4,"\u29b9":e.MO.BIN4,"\u29ba":e.MO.BIN4,"\u29bb":e.MO.BIN4,"\u29bc":e.MO.BIN4,"\u29bd":e.MO.BIN4,"\u29be":e.MO.BIN4,"\u29bf":e.MO.BIN4,"\u29c0":e.MO.REL,"\u29c1":e.MO.REL,"\u29c2":e.MO.BIN3,"\u29c3":e.MO.BIN3,"\u29c4":e.MO.BIN4,"\u29c5":e.MO.BIN4,"\u29c6":e.MO.BIN4,"\u29c7":e.MO.BIN4,"\u29c8":e.MO.BIN4,"\u29c9":e.MO.BIN3,"\u29ca":e.MO.BIN3,"\u29cb":e.MO.BIN3,"\u29cc":e.MO.BIN3,"\u29cd":e.MO.BIN3,"\u29ce":e.MO.REL,"\u29cf":e.MO.REL,"\u29cf\u0338":e.MO.REL,"\u29d0":e.MO.REL,"\u29d0\u0338":e.MO.REL,"\u29d1":e.MO.REL,"\u29d2":e.MO.REL,"\u29d3":e.MO.REL,"\u29d4":e.MO.REL,"\u29d5":e.MO.REL,"\u29d6":e.MO.BIN4,"\u29d7":e.MO.BIN4,"\u29d8":e.MO.BIN3,"\u29d9":e.MO.BIN3,"\u29db":e.MO.BIN3,"\u29dc":e.MO.BIN3,"\u29dd":e.MO.BIN3,"\u29de":e.MO.REL,"\u29df":e.MO.BIN3,"\u29e0":e.MO.BIN3,"\u29e1":e.MO.REL,"\u29e2":e.MO.BIN4,"\u29e3":e.MO.REL,"\u29e4":e.MO.REL,"\u29e5":e.MO.REL,"\u29e6":e.MO.REL,"\u29e7":e.MO.BIN3,"\u29e8":e.MO.BIN3,"\u29e9":e.MO.BIN3,"\u29ea":e.MO.BIN3,"\u29eb":e.MO.BIN3,"\u29ec":e.MO.BIN3,"\u29ed":e.MO.BIN3,"\u29ee":e.MO.BIN3,"\u29ef":e.MO.BIN3,"\u29f0":e.MO.BIN3,"\u29f1":e.MO.BIN3,"\u29f2":e.MO.BIN3,"\u29f3":e.MO.BIN3,"\u29f4":e.MO.REL,"\u29f5":e.MO.BIN4,"\u29f6":e.MO.BIN4,"\u29f7":e.MO.BIN4,"\u29f8":e.MO.BIN3,"\u29f9":e.MO.BIN3,"\u29fa":e.MO.BIN3,"\u29fb":e.MO.BIN3,"\u29fe":e.MO.BIN4,"\u29ff":e.MO.BIN4,"\u2a1d":e.MO.BIN3,"\u2a1e":e.MO.BIN3,"\u2a1f":e.MO.BIN3,"\u2a20":e.MO.BIN3,"\u2a21":e.MO.BIN3,"\u2a22":e.MO.BIN4,"\u2a23":e.MO.BIN4,"\u2a24":e.MO.BIN4,"\u2a25":e.MO.BIN4,"\u2a26":e.MO.BIN4,"\u2a27":e.MO.BIN4,"\u2a28":e.MO.BIN4,"\u2a29":e.MO.BIN4,"\u2a2a":e.MO.BIN4,"\u2a2b":e.MO.BIN4,"\u2a2c":e.MO.BIN4,"\u2a2d":e.MO.BIN4,"\u2a2e":e.MO.BIN4,"\u2a2f":e.MO.BIN4,"\u2a30":e.MO.BIN4,"\u2a31":e.MO.BIN4,"\u2a32":e.MO.BIN4,"\u2a33":e.MO.BIN4,"\u2a34":e.MO.BIN4,"\u2a35":e.MO.BIN4,"\u2a36":e.MO.BIN4,"\u2a37":e.MO.BIN4,"\u2a38":e.MO.BIN4,"\u2a39":e.MO.BIN4,"\u2a3a":e.MO.BIN4,"\u2a3b":e.MO.BIN4,"\u2a3c":e.MO.BIN4,"\u2a3d":e.MO.BIN4,"\u2a3e":e.MO.BIN4,"\u2a3f":e.MO.BIN4,"\u2a40":e.MO.BIN4,"\u2a41":e.MO.BIN4,"\u2a42":e.MO.BIN4,"\u2a43":e.MO.BIN4,"\u2a44":e.MO.BIN4,"\u2a45":e.MO.BIN4,"\u2a46":e.MO.BIN4,"\u2a47":e.MO.BIN4,"\u2a48":e.MO.BIN4,"\u2a49":e.MO.BIN4,"\u2a4a":e.MO.BIN4,"\u2a4b":e.MO.BIN4,"\u2a4c":e.MO.BIN4,"\u2a4d":e.MO.BIN4,"\u2a4e":e.MO.BIN4,"\u2a4f":e.MO.BIN4,"\u2a50":e.MO.BIN4,"\u2a51":e.MO.BIN4,"\u2a52":e.MO.BIN4,"\u2a53":e.MO.BIN4,"\u2a54":e.MO.BIN4,"\u2a55":e.MO.BIN4,"\u2a56":e.MO.BIN4,"\u2a57":e.MO.BIN4,"\u2a58":e.MO.BIN4,"\u2a59":e.MO.REL,"\u2a5a":e.MO.BIN4,"\u2a5b":e.MO.BIN4,"\u2a5c":e.MO.BIN4,"\u2a5d":e.MO.BIN4,"\u2a5e":e.MO.BIN4,"\u2a5f":e.MO.BIN4,"\u2a60":e.MO.BIN4,"\u2a61":e.MO.BIN4,"\u2a62":e.MO.BIN4,"\u2a63":e.MO.BIN4,"\u2a64":e.MO.BIN4,"\u2a65":e.MO.BIN4,"\u2a66":e.MO.REL,"\u2a67":e.MO.REL,"\u2a68":e.MO.REL,"\u2a69":e.MO.REL,"\u2a6a":e.MO.REL,"\u2a6b":e.MO.REL,"\u2a6c":e.MO.REL,"\u2a6d":e.MO.REL,"\u2a6e":e.MO.REL,"\u2a6f":e.MO.REL,"\u2a70":e.MO.REL,"\u2a71":e.MO.BIN4,"\u2a72":e.MO.BIN4,"\u2a73":e.MO.REL,"\u2a74":e.MO.REL,"\u2a75":e.MO.REL,"\u2a76":e.MO.REL,"\u2a77":e.MO.REL,"\u2a78":e.MO.REL,"\u2a79":e.MO.REL,"\u2a7a":e.MO.REL,"\u2a7b":e.MO.REL,"\u2a7c":e.MO.REL,"\u2a7d":e.MO.REL,"\u2a7d\u0338":e.MO.REL,"\u2a7e":e.MO.REL,"\u2a7e\u0338":e.MO.REL,"\u2a7f":e.MO.REL,"\u2a80":e.MO.REL,"\u2a81":e.MO.REL,"\u2a82":e.MO.REL,"\u2a83":e.MO.REL,"\u2a84":e.MO.REL,"\u2a85":e.MO.REL,"\u2a86":e.MO.REL,"\u2a87":e.MO.REL,"\u2a88":e.MO.REL,"\u2a89":e.MO.REL,"\u2a8a":e.MO.REL,"\u2a8b":e.MO.REL,"\u2a8c":e.MO.REL,"\u2a8d":e.MO.REL,"\u2a8e":e.MO.REL,"\u2a8f":e.MO.REL,"\u2a90":e.MO.REL,"\u2a91":e.MO.REL,"\u2a92":e.MO.REL,"\u2a93":e.MO.REL,"\u2a94":e.MO.REL,"\u2a95":e.MO.REL,"\u2a96":e.MO.REL,"\u2a97":e.MO.REL,"\u2a98":e.MO.REL,"\u2a99":e.MO.REL,"\u2a9a":e.MO.REL,"\u2a9b":e.MO.REL,"\u2a9c":e.MO.REL,"\u2a9d":e.MO.REL,"\u2a9e":e.MO.REL,"\u2a9f":e.MO.REL,"\u2aa0":e.MO.REL,"\u2aa1":e.MO.REL,"\u2aa1\u0338":e.MO.REL,"\u2aa2":e.MO.REL,"\u2aa2\u0338":e.MO.REL,"\u2aa3":e.MO.REL,"\u2aa4":e.MO.REL,"\u2aa5":e.MO.REL,"\u2aa6":e.MO.REL,"\u2aa7":e.MO.REL,"\u2aa8":e.MO.REL,"\u2aa9":e.MO.REL,"\u2aaa":e.MO.REL,"\u2aab":e.MO.REL,"\u2aac":e.MO.REL,"\u2aad":e.MO.REL,"\u2aae":e.MO.REL,"\u2aaf":e.MO.REL,"\u2aaf\u0338":e.MO.REL,"\u2ab0":e.MO.REL,"\u2ab0\u0338":e.MO.REL,"\u2ab1":e.MO.REL,"\u2ab2":e.MO.REL,"\u2ab3":e.MO.REL,"\u2ab4":e.MO.REL,"\u2ab5":e.MO.REL,"\u2ab6":e.MO.REL,"\u2ab7":e.MO.REL,"\u2ab8":e.MO.REL,"\u2ab9":e.MO.REL,"\u2aba":e.MO.REL,"\u2abb":e.MO.REL,"\u2abc":e.MO.REL,"\u2abd":e.MO.REL,"\u2abe":e.MO.REL,"\u2abf":e.MO.REL,"\u2ac0":e.MO.REL,"\u2ac1":e.MO.REL,"\u2ac2":e.MO.REL,"\u2ac3":e.MO.REL,"\u2ac4":e.MO.REL,"\u2ac5":e.MO.REL,"\u2ac6":e.MO.REL,"\u2ac7":e.MO.REL,"\u2ac8":e.MO.REL,"\u2ac9":e.MO.REL,"\u2aca":e.MO.REL,"\u2acb":e.MO.REL,"\u2acc":e.MO.REL,"\u2acd":e.MO.REL,"\u2ace":e.MO.REL,"\u2acf":e.MO.REL,"\u2ad0":e.MO.REL,"\u2ad1":e.MO.REL,"\u2ad2":e.MO.REL,"\u2ad3":e.MO.REL,"\u2ad4":e.MO.REL,"\u2ad5":e.MO.REL,"\u2ad6":e.MO.REL,"\u2ad7":e.MO.REL,"\u2ad8":e.MO.REL,"\u2ad9":e.MO.REL,"\u2ada":e.MO.REL,"\u2adb":e.MO.REL,"\u2add":e.MO.REL,"\u2add\u0338":e.MO.REL,"\u2ade":e.MO.REL,"\u2adf":e.MO.REL,"\u2ae0":e.MO.REL,"\u2ae1":e.MO.REL,"\u2ae2":e.MO.REL,"\u2ae3":e.MO.REL,"\u2ae4":e.MO.REL,"\u2ae5":e.MO.REL,"\u2ae6":e.MO.REL,"\u2ae7":e.MO.REL,"\u2ae8":e.MO.REL,"\u2ae9":e.MO.REL,"\u2aea":e.MO.REL,"\u2aeb":e.MO.REL,"\u2aec":e.MO.REL,"\u2aed":e.MO.REL,"\u2aee":e.MO.REL,"\u2aef":e.MO.REL,"\u2af0":e.MO.REL,"\u2af1":e.MO.REL,"\u2af2":e.MO.REL,"\u2af3":e.MO.REL,"\u2af4":e.MO.BIN4,"\u2af5":e.MO.BIN4,"\u2af6":e.MO.BIN4,"\u2af7":e.MO.REL,"\u2af8":e.MO.REL,"\u2af9":e.MO.REL,"\u2afa":e.MO.REL,"\u2afb":e.MO.BIN4,"\u2afd":e.MO.BIN4,"\u2afe":e.MO.BIN3,"\u2b45":e.MO.RELSTRETCH,"\u2b46":e.MO.RELSTRETCH,"\u3008":e.MO.OPEN,"\u3009":e.MO.CLOSE,"\ufe37":e.MO.WIDEACCENT,"\ufe38":e.MO.WIDEACCENT}},e.OPTABLE.infix["^"]=e.MO.WIDEREL,e.OPTABLE.infix._=e.MO.WIDEREL,e.OPTABLE.infix["\u2adc"]=e.MO.REL},9259:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s};Object.defineProperty(e,"__esModule",{value:!0}),e.SerializedMmlVisitor=e.toEntity=e.DATAMJX=void 0;var a=r(6325),l=r(9007),u=r(450);e.DATAMJX="data-mjx-";e.toEntity=function(t){return"&#x"+t.codePointAt(0).toString(16).toUpperCase()+";"};var c=function(t){function r(){return null!==t&&t.apply(this,arguments)||this}return o(r,t),r.prototype.visitTree=function(t){return this.visitNode(t,"")},r.prototype.visitTextNode=function(t,e){return this.quoteHTML(t.getText())},r.prototype.visitXMLNode=function(t,e){return e+t.getSerializedXML()},r.prototype.visitInferredMrowNode=function(t,e){var r,n,o=[];try{for(var s=i(t.childNodes),a=s.next();!a.done;a=s.next()){var l=a.value;o.push(this.visitNode(l,e))}}catch(t){r={error:t}}finally{try{a&&!a.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}return o.join("\n")},r.prototype.visitTeXAtomNode=function(t,e){var r=this.childNodeMml(t,e+" ","\n");return e+""+(r.match(/\S/)?"\n"+r+e:"")+""},r.prototype.visitAnnotationNode=function(t,e){return e+""+this.childNodeMml(t,"","")+""},r.prototype.visitDefault=function(t,e){var r=t.kind,n=s(t.isToken||0===t.childNodes.length?["",""]:["\n",e],2),o=n[0],i=n[1],a=this.childNodeMml(t,e+" ",o);return e+"<"+r+this.getAttributes(t)+">"+(a.match(/\S/)?o+a+i:"")+""},r.prototype.childNodeMml=function(t,e,r){var n,o,s="";try{for(var a=i(t.childNodes),l=a.next();!l.done;l=a.next()){var u=l.value;s+=this.visitNode(u,e)+r}}catch(t){n={error:t}}finally{try{l&&!l.done&&(o=a.return)&&o.call(a)}finally{if(n)throw n.error}}return s},r.prototype.getAttributes=function(t){var e,r,n=[],o=this.constructor.defaultAttributes[t.kind]||{},s=Object.assign({},o,this.getDataAttributes(t),t.attributes.getAllAttributes()),a=this.constructor.variants;s.hasOwnProperty("mathvariant")&&a.hasOwnProperty(s.mathvariant)&&(s.mathvariant=a[s.mathvariant]);try{for(var l=i(Object.keys(s)),u=l.next();!u.done;u=l.next()){var c=u.value,p=String(s[c]);void 0!==p&&n.push(c+'="'+this.quoteHTML(p)+'"')}}catch(t){e={error:t}}finally{try{u&&!u.done&&(r=l.return)&&r.call(l)}finally{if(e)throw e.error}}return n.length?" "+n.join(" "):""},r.prototype.getDataAttributes=function(t){var e={},r=t.attributes.getExplicit("mathvariant"),n=this.constructor.variants;r&&n.hasOwnProperty(r)&&this.setDataAttribute(e,"variant",r),t.getProperty("variantForm")&&this.setDataAttribute(e,"alternate","1"),t.getProperty("pseudoscript")&&this.setDataAttribute(e,"pseudoscript","true"),!1===t.getProperty("autoOP")&&this.setDataAttribute(e,"auto-op","false");var o=t.getProperty("texClass");if(void 0!==o){var i=!0;if(o===l.TEXCLASS.OP&&t.isKind("mi")){var s=t.getText();i=!(s.length>1&&s.match(u.MmlMi.operatorName))}i&&this.setDataAttribute(e,"texclass",o<0?"NONE":l.TEXCLASSNAMES[o])}return t.getProperty("scriptlevel")&&!1===t.getProperty("useHeight")&&this.setDataAttribute(e,"smallmatrix","true"),e},r.prototype.setDataAttribute=function(t,r,n){t[e.DATAMJX+r]=n},r.prototype.quoteHTML=function(t){return t.replace(/&/g,"&").replace(//g,">").replace(/\"/g,""").replace(/[\uD800-\uDBFF]./g,e.toEntity).replace(/[\u0080-\uD7FF\uE000-\uFFFF]/g,e.toEntity)},r.variants={"-tex-calligraphic":"script","-tex-bold-calligraphic":"bold-script","-tex-oldstyle":"normal","-tex-bold-oldstyle":"bold","-tex-mathit":"italic"},r.defaultAttributes={math:{xmlns:"http://www.w3.org/1998/Math/MathML"}},r}(a.MmlVisitor);e.SerializedMmlVisitor=c},2975:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractOutputJax=void 0;var n=r(7233),o=r(7525),i=function(){function t(t){void 0===t&&(t={}),this.adaptor=null;var e=this.constructor;this.options=n.userOptions(n.defaultOptions({},e.OPTIONS),t),this.postFilters=new o.FunctionList}return Object.defineProperty(t.prototype,"name",{get:function(){return this.constructor.NAME},enumerable:!1,configurable:!0}),t.prototype.setAdaptor=function(t){this.adaptor=t},t.prototype.initialize=function(){},t.prototype.reset=function(){for(var t=[],e=0;e=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractEmptyNode=e.AbstractNode=void 0;var i=function(){function t(t,e,r){var n,i;void 0===e&&(e={}),void 0===r&&(r=[]),this.factory=t,this.parent=null,this.properties={},this.childNodes=[];try{for(var s=o(Object.keys(e)),a=s.next();!a.done;a=s.next()){var l=a.value;this.setProperty(l,e[l])}}catch(t){n={error:t}}finally{try{a&&!a.done&&(i=s.return)&&i.call(s)}finally{if(n)throw n.error}}r.length&&this.setChildren(r)}return Object.defineProperty(t.prototype,"kind",{get:function(){return"unknown"},enumerable:!1,configurable:!0}),t.prototype.setProperty=function(t,e){this.properties[t]=e},t.prototype.getProperty=function(t){return this.properties[t]},t.prototype.getPropertyNames=function(){return Object.keys(this.properties)},t.prototype.getAllProperties=function(){return this.properties},t.prototype.removeProperty=function(){for(var t,e,r=[],n=0;n=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},i=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},s=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},a=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.HTMLDocument=void 0;var l=r(5722),u=r(7233),c=r(3363),p=r(3335),f=r(5138),h=r(4474),d=function(t){function e(e,r,n){var o=this,i=s(u.separateOptions(n,f.HTMLDomStrings.OPTIONS),2),a=i[0],l=i[1];return(o=t.call(this,e,r,a)||this).domStrings=o.options.DomStrings||new f.HTMLDomStrings(l),o.domStrings.adaptor=r,o.styles=[],o}return o(e,t),e.prototype.findPosition=function(t,e,r,n){var o,i,l=this.adaptor;try{for(var u=a(n[t]),c=u.next();!c.done;c=u.next()){var p=c.value,f=s(p,2),h=f[0],d=f[1];if(e<=d&&"#text"===l.kind(h))return{node:h,n:Math.max(e,0),delim:r};e-=d}}catch(t){o={error:t}}finally{try{c&&!c.done&&(i=u.return)&&i.call(u)}finally{if(o)throw o.error}}return{node:null,n:0,delim:r}},e.prototype.mathItem=function(t,e,r){var n=t.math,o=this.findPosition(t.n,t.start.n,t.open,r),i=this.findPosition(t.n,t.end.n,t.close,r);return new this.options.MathItem(n,e,t.display,o,i)},e.prototype.findMath=function(t){var e,r,n,o,i,l,c,p,f;if(!this.processed.isSet("findMath")){this.adaptor.document=this.document,t=u.userOptions({elements:this.options.elements||[this.adaptor.body(this.document)]},t);try{for(var h=a(this.adaptor.getElements(t.elements,this.document)),d=h.next();!d.done;d=h.next()){var y=d.value,O=s([null,null],2),M=O[0],E=O[1];try{for(var v=(n=void 0,a(this.inputJax)),b=v.next();!b.done;b=v.next()){var m=b.value,g=new this.options.MathList;if(m.processStrings){null===M&&(M=(i=s(this.domStrings.find(y),2))[0],E=i[1]);try{for(var L=(l=void 0,a(m.findMath(M))),N=L.next();!N.done;N=L.next()){var R=N.value;g.push(this.mathItem(R,m,E))}}catch(t){l={error:t}}finally{try{N&&!N.done&&(c=L.return)&&c.call(L)}finally{if(l)throw l.error}}}else try{for(var T=(p=void 0,a(m.findMath(y))),S=T.next();!S.done;S=T.next()){R=S.value;var A=new this.options.MathItem(R.math,m,R.display,R.start,R.end);g.push(A)}}catch(t){p={error:t}}finally{try{S&&!S.done&&(f=T.return)&&f.call(T)}finally{if(p)throw p.error}}this.math.merge(g)}}catch(t){n={error:t}}finally{try{b&&!b.done&&(o=v.return)&&o.call(v)}finally{if(n)throw n.error}}}}catch(t){e={error:t}}finally{try{d&&!d.done&&(r=h.return)&&r.call(h)}finally{if(e)throw e.error}}this.processed.set("findMath")}return this},e.prototype.updateDocument=function(){return this.processed.isSet("updateDocument")||(this.addPageElements(),this.addStyleSheet(),t.prototype.updateDocument.call(this),this.processed.set("updateDocument")),this},e.prototype.addPageElements=function(){var t=this.adaptor.body(this.document),e=this.documentPageElements();e&&this.adaptor.append(t,e)},e.prototype.addStyleSheet=function(){var t=this.documentStyleSheet(),e=this.adaptor;if(t&&!e.parent(t)){var r=e.head(this.document),n=this.findSheet(r,e.getAttribute(t,"id"));n?e.replace(t,n):e.append(r,t)}},e.prototype.findSheet=function(t,e){var r,n;if(e)try{for(var o=a(this.adaptor.tags(t,"style")),i=o.next();!i.done;i=o.next()){var s=i.value;if(this.adaptor.getAttribute(s,"id")===e)return s}}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}return null},e.prototype.removeFromDocument=function(t){var e,r;if(void 0===t&&(t=!1),this.processed.isSet("updateDocument"))try{for(var n=a(this.math),o=n.next();!o.done;o=n.next()){var i=o.value;i.state()>=h.STATE.INSERTED&&i.state(h.STATE.TYPESET,t)}}catch(t){e={error:t}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}return this.processed.clear("updateDocument"),this},e.prototype.documentStyleSheet=function(){return this.outputJax.styleSheet(this)},e.prototype.documentPageElements=function(){return this.outputJax.pageElements(this)},e.prototype.addStyles=function(t){this.styles.push(t)},e.prototype.getStyles=function(){return this.styles},e.KIND="HTML",e.OPTIONS=i(i({},l.AbstractMathDocument.OPTIONS),{renderActions:u.expandable(i(i({},l.AbstractMathDocument.OPTIONS.renderActions),{styles:[h.STATE.INSERTED+1,"","updateStyleSheet",!1]})),MathList:p.HTMLMathList,MathItem:c.HTMLMathItem,DomStrings:null}),e}(l.AbstractMathDocument);e.HTMLDocument=d},5138:function(t,e,r){var n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s};Object.defineProperty(e,"__esModule",{value:!0}),e.HTMLDomStrings=void 0;var o=r(7233),i=function(){function t(t){void 0===t&&(t=null);var e=this.constructor;this.options=o.userOptions(o.defaultOptions({},e.OPTIONS),t),this.init(),this.getPatterns()}return t.prototype.init=function(){this.strings=[],this.string="",this.snodes=[],this.nodes=[],this.stack=[]},t.prototype.getPatterns=function(){var t=o.makeArray(this.options.skipHtmlTags),e=o.makeArray(this.options.ignoreHtmlClass),r=o.makeArray(this.options.processHtmlClass);this.skipHtmlTags=new RegExp("^(?:"+t.join("|")+")$","i"),this.ignoreHtmlClass=new RegExp("(?:^| )(?:"+e.join("|")+")(?: |$)"),this.processHtmlClass=new RegExp("(?:^| )(?:"+r+")(?: |$)")},t.prototype.pushString=function(){this.string.match(/\S/)&&(this.strings.push(this.string),this.nodes.push(this.snodes)),this.string="",this.snodes=[]},t.prototype.extendString=function(t,e){this.snodes.push([t,e.length]),this.string+=e},t.prototype.handleText=function(t,e){return e||this.extendString(t,this.adaptor.value(t)),this.adaptor.next(t)},t.prototype.handleTag=function(t,e){if(!e){var r=this.options.includeHtmlTags[this.adaptor.kind(t)];this.extendString(t,r)}return this.adaptor.next(t)},t.prototype.handleContainer=function(t,e){this.pushString();var r=this.adaptor.getAttribute(t,"class")||"",n=this.adaptor.kind(t)||"",o=this.processHtmlClass.exec(r),i=t;return!this.adaptor.firstChild(t)||this.adaptor.getAttribute(t,"data-MJX")||!o&&this.skipHtmlTags.exec(n)?i=this.adaptor.next(t):(this.adaptor.next(t)&&this.stack.push([this.adaptor.next(t),e]),i=this.adaptor.firstChild(t),e=(e||this.ignoreHtmlClass.exec(r))&&!o),[i,e]},t.prototype.handleOther=function(t,e){return this.pushString(),this.adaptor.next(t)},t.prototype.find=function(t){var e,r;this.init();for(var o=this.adaptor.next(t),i=!1,s=this.options.includeHtmlTags;t&&t!==o;){var a=this.adaptor.kind(t);"#text"===a?t=this.handleText(t,i):s.hasOwnProperty(a)?t=this.handleTag(t,i):a?(t=(e=n(this.handleContainer(t,i),2))[0],i=e[1]):t=this.handleOther(t,i),!t&&this.stack.length&&(this.pushString(),t=(r=n(this.stack.pop(),2))[0],i=r[1])}this.pushString();var l=[this.strings,this.nodes];return this.init(),l},t.OPTIONS={skipHtmlTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],includeHtmlTags:{br:"\n",wbr:"","#comment":""},ignoreHtmlClass:"mathjax_ignore",processHtmlClass:"mathjax_process"},t}();e.HTMLDomStrings=i},3726:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.HTMLHandler=void 0;var i=r(3670),s=r(3683),a=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.documentClass=s.HTMLDocument,e}return o(e,t),e.prototype.handlesDocument=function(t){var e=this.adaptor;if("string"==typeof t)try{t=e.parse(t,"text/html")}catch(t){}return t instanceof e.window.Document||t instanceof e.window.HTMLElement||t instanceof e.window.DocumentFragment},e.prototype.create=function(e,r){var n=this.adaptor;if("string"==typeof e)e=n.parse(e,"text/html");else if(e instanceof n.window.HTMLElement||e instanceof n.window.DocumentFragment){var o=e;e=n.parse("","text/html"),n.append(n.body(e),o)}return t.prototype.create.call(this,e,r)},e}(i.AbstractHandler);e.HTMLHandler=a},3363:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.HTMLMathItem=void 0;var i=r(4474),s=function(t){function e(e,r,n,o,i){return void 0===n&&(n=!0),void 0===o&&(o={node:null,n:0,delim:""}),void 0===i&&(i={node:null,n:0,delim:""}),t.call(this,e,r,n,o,i)||this}return o(e,t),Object.defineProperty(e.prototype,"adaptor",{get:function(){return this.inputJax.adaptor},enumerable:!1,configurable:!0}),e.prototype.updateDocument=function(t){if(this.state()=i.STATE.TYPESET){var e=this.adaptor,r=this.start.node,n=e.text("");if(t){var o=this.start.delim+this.math+this.end.delim;if(this.inputJax.processStrings)n=e.text(o);else{var s=e.parse(o,"text/html");n=e.firstChild(e.body(s))}}e.parent(r)&&e.replace(n,r),this.start.node=this.end.node=n,this.start.n=this.end.n=0}},e}(i.AbstractMathItem);e.HTMLMathItem=s},3335:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.HTMLMathList=void 0;var i=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e}(r(9e3).AbstractMathList);e.HTMLMathList=i},5713:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.mathjax=void 0;var n=r(805),o=r(4542);e.mathjax={version:"3.1.4",handlers:new n.HandlerList,document:function(t,r){return e.mathjax.handlers.document(t,r)},handleRetriesFor:o.handleRetriesFor,retryAfter:o.retryAfter,asyncLoad:null}},9923:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.asyncLoad=void 0;var n=r(5713);e.asyncLoad=function(t){return n.mathjax.asyncLoad?new Promise((function(e,r){var o=n.mathjax.asyncLoad(t);o instanceof Promise?o.then((function(t){return e(t)})).catch((function(t){return r(t)})):e(o)})):Promise.reject("Can't load '"+t+"': No asyncLoad method specified")}},6469:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.BBox=e.BBoxStyleAdjust=void 0;var n=r(6010);e.BBoxStyleAdjust=[["borderTopWidth","h"],["borderRightWidth","w"],["borderBottomWidth","d"],["borderLeftWidth","w",0],["paddingTop","h"],["paddingRight","w"],["paddingBottom","d"],["paddingLeft","w",0]];var o=function(){function t(t){void 0===t&&(t={w:0,h:-n.BIGDIMEN,d:-n.BIGDIMEN}),this.w=t.w||0,this.h="h"in t?t.h:-n.BIGDIMEN,this.d="d"in t?t.d:-n.BIGDIMEN,this.L=this.R=this.ic=this.sk=0,this.scale=this.rscale=1,this.pwidth=""}return t.zero=function(){return new t({h:0,d:0,w:0})},t.empty=function(){return new t},t.prototype.empty=function(){return this.w=0,this.h=this.d=-n.BIGDIMEN,this},t.prototype.clean=function(){this.w===-n.BIGDIMEN&&(this.w=0),this.h===-n.BIGDIMEN&&(this.h=0),this.d===-n.BIGDIMEN&&(this.d=0)},t.prototype.rescale=function(t){this.w*=t,this.h*=t,this.d*=t},t.prototype.combine=function(t,e,r){void 0===e&&(e=0),void 0===r&&(r=0);var n=t.rscale,o=e+n*(t.w+t.L+t.R),i=r+n*t.h,s=n*t.d-r;o>this.w&&(this.w=o),i>this.h&&(this.h=i),s>this.d&&(this.d=s)},t.prototype.append=function(t){var e=t.rscale;this.w+=e*(t.w+t.L+t.R),e*t.h>this.h&&(this.h=e*t.h),e*t.d>this.d&&(this.d=e*t.d)},t.prototype.updateFrom=function(t){this.h=t.h,this.d=t.d,this.w=t.w,t.pwidth&&(this.pwidth=t.pwidth)},t.fullWidth="100%",t}();e.BBox=o},6751:function(t,e){var r,n=this&&this.__extends||(r=function(t,e){return(r=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])})(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 n(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),o=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},s=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r",gtdot:"\u22d7",harrw:"\u21ad",hbar:"\u210f",hellip:"\u2026",hookleftarrow:"\u21a9",hookrightarrow:"\u21aa",imath:"\u0131",infin:"\u221e",intcal:"\u22ba",iota:"\u03b9",jmath:"\u0237",kappa:"\u03ba",kappav:"\u03f0",lEg:"\u2a8b",lambda:"\u03bb",lap:"\u2a85",larrlp:"\u21ab",larrtl:"\u21a2",lbrace:"{",lbrack:"[",le:"\u2264",leftleftarrows:"\u21c7",leftthreetimes:"\u22cb",lessdot:"\u22d6",lmoust:"\u23b0",lnE:"\u2268",lnap:"\u2a89",lne:"\u2a87",lnsim:"\u22e6",longmapsto:"\u27fc",looparrowright:"\u21ac",lowast:"\u2217",loz:"\u25ca",lt:"<",ltimes:"\u22c9",ltri:"\u25c3",macr:"\xaf",malt:"\u2720",mho:"\u2127",mu:"\u03bc",multimap:"\u22b8",nLeftarrow:"\u21cd",nLeftrightarrow:"\u21ce",nRightarrow:"\u21cf",nVDash:"\u22af",nVdash:"\u22ae",natur:"\u266e",nearr:"\u2197",nharr:"\u21ae",nlarr:"\u219a",not:"\xac",nrarr:"\u219b",nu:"\u03bd",nvDash:"\u22ad",nvdash:"\u22ac",nwarr:"\u2196",omega:"\u03c9",omicron:"\u03bf",or:"\u2228",osol:"\u2298",period:".",phi:"\u03c6",phiv:"\u03d5",pi:"\u03c0",piv:"\u03d6",prap:"\u2ab7",precnapprox:"\u2ab9",precneqq:"\u2ab5",precnsim:"\u22e8",prime:"\u2032",psi:"\u03c8",quot:'"',rarrtl:"\u21a3",rbrace:"}",rbrack:"]",rho:"\u03c1",rhov:"\u03f1",rightrightarrows:"\u21c9",rightthreetimes:"\u22cc",ring:"\u02da",rmoust:"\u23b1",rtimes:"\u22ca",rtri:"\u25b9",scap:"\u2ab8",scnE:"\u2ab6",scnap:"\u2aba",scnsim:"\u22e9",sdot:"\u22c5",searr:"\u2198",sect:"\xa7",sharp:"\u266f",sigma:"\u03c3",sigmav:"\u03c2",simne:"\u2246",smile:"\u2323",spades:"\u2660",sub:"\u2282",subE:"\u2ac5",subnE:"\u2acb",subne:"\u228a",supE:"\u2ac6",supnE:"\u2acc",supne:"\u228b",swarr:"\u2199",tau:"\u03c4",theta:"\u03b8",thetav:"\u03d1",tilde:"\u02dc",times:"\xd7",triangle:"\u25b5",triangleq:"\u225c",upsi:"\u03c5",upuparrows:"\u21c8",veebar:"\u22bb",vellip:"\u22ee",weierp:"\u2118",xi:"\u03be",yen:"\xa5",zeta:"\u03b6",zigrarr:"\u21dd",nbsp:"\xa0",rsquo:"\u2019",lsquo:"\u2018"};var i={};function s(t,r){if("#"===r.charAt(0))return a(r.slice(1));if(e.entities[r])return e.entities[r];if(e.options.loadMissingEntities){var s=r.match(/^[a-zA-Z](fr|scr|opf)$/)?RegExp.$1:r.charAt(0).toLowerCase();i[s]||(i[s]=!0,n.retryAfter(o.asyncLoad("./util/entities/"+s+".js")))}return t}function a(t){var e="x"===t.charAt(0)?parseInt(t.slice(1),16):parseInt(t);return String.fromCodePoint(e)}e.add=function(t,r){Object.assign(e.entities,t),i[r]=!0},e.remove=function(t){delete e.entities[t]},e.translate=function(t){return t.replace(/&([a-z][a-z0-9]*|#(?:[0-9]+|x[0-9a-f]+));/gi,s)},e.numeric=a},7525:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},a=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},n=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.LinkedList=e.ListItem=e.END=void 0,e.END=Symbol();var i=function(t){void 0===t&&(t=null),this.next=null,this.prev=null,this.data=t};e.ListItem=i;var s=function(){function t(){for(var t=[],o=0;o1;){var u=i.shift(),c=i.shift();u.merge(c,e),i.push(u)}return i.length&&(this.list=i[0].list),this},t.prototype.merge=function(t,n){var o,i,s,a,l;void 0===n&&(n=null),null===n&&(n=this.isBefore.bind(this));for(var u=this.list.next,c=t.list.next;u.data!==e.END&&c.data!==e.END;)n(c.data,u.data)?(o=r([u,c],2),c.prev.next=o[0],u.prev.next=o[1],i=r([u.prev,c.prev],2),c.prev=i[0],u.prev=i[1],s=r([t.list,this.list],2),this.list.prev.next=s[0],t.list.prev.next=s[1],a=r([t.list.prev,this.list.prev],2),this.list.prev=a[0],t.list.prev=a[1],u=(l=r([c.next,u],2))[0],c=l[1]):u=u.next;return c.data!==e.END&&(this.list.prev.next=t.list.next,t.list.next.prev=this.list.prev,t.list.prev.next=this.list,this.list.prev=t.list.prev,t.list.next=t.list.prev=t.list),this},t}();e.LinkedList=s},7233:function(t,e){var r=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;re.length}}}},t.prototype.add=function(e,r){void 0===r&&(r=t.DEFAULTPRIORITY);var n=this.items.length;do{n--}while(n>=0&&r=0&&this.items[e].item!==t);e>=0&&this.items.splice(e,1)},t.prototype.toArray=function(){return Array.from(this)},t.DEFAULTPRIORITY=5,t}();e.PrioritizedList=r},4542:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.retryAfter=e.handleRetriesFor=void 0,e.handleRetriesFor=function(t){return new Promise((function e(r,n){try{r(t())}catch(t){t.retry&&t.retry instanceof Promise?t.retry.then((function(){return e(r,n)})).catch((function(t){return n(t)})):t.restart&&t.restart.isCallback?MathJax.Callback.After((function(){return e(r,n)}),t.restart):n(t)}}))},e.retryAfter=function(t){var e=new Error("MathJax retry");throw e.retry=t,e}},4139:function(t,e){var r=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CssStyles=void 0;var n=function(){function t(t){void 0===t&&(t=null),this.styles={},this.addStyles(t)}return Object.defineProperty(t.prototype,"cssText",{get:function(){return this.getStyleString()},enumerable:!1,configurable:!0}),t.prototype.addStyles=function(t){var e,n;if(t)try{for(var o=r(Object.keys(t)),i=o.next();!i.done;i=o.next()){var s=i.value;this.styles[s]||(this.styles[s]={}),Object.assign(this.styles[s],t[s])}}catch(t){e={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(e)throw e.error}}},t.prototype.removeStyles=function(){for(var t,e,n=[],o=0;o=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,i=r.call(t),s=[];try{for(;(void 0===e||e-- >0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r1;)e.shift(),r.push(e.shift());return r}function l(t){var e,n,o=a(this.styles[t]);0===o.length&&o.push(""),1===o.length&&o.push(o[0]),2===o.length&&o.push(o[0]),3===o.length&&o.push(o[1]);try{for(var i=r(v.connect[t].children),s=i.next();!s.done;s=i.next()){var l=s.value;this.setStyle(this.childName(t,l),o.shift())}}catch(t){e={error:t}}finally{try{s&&!s.done&&(n=i.return)&&n.call(i)}finally{if(e)throw e.error}}}function u(t){var e,n,o=v.connect[t].children,i=[];try{for(var s=r(o),a=s.next();!a.done;a=s.next()){var l=a.value,u=this.styles[t+"-"+l];if(!u)return void delete this.styles[t];i.push(u)}}catch(t){e={error:t}}finally{try{a&&!a.done&&(n=s.return)&&n.call(s)}finally{if(e)throw e.error}}i[3]===i[1]&&(i.pop(),i[2]===i[0]&&(i.pop(),i[1]===i[0]&&i.pop())),this.styles[t]=i.join(" ")}function c(t){var e,n;try{for(var o=r(v.connect[t].children),i=o.next();!i.done;i=o.next()){var s=i.value;this.setStyle(this.childName(t,s),this.styles[t])}}catch(t){e={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(e)throw e.error}}}function p(t){var e,i,s=o([],n(v.connect[t].children)),a=this.styles[this.childName(t,s.shift())];try{for(var l=r(s),u=l.next();!u.done;u=l.next()){var c=u.value;if(this.styles[this.childName(t,c)]!==a)return void delete this.styles[t]}}catch(t){e={error:t}}finally{try{u&&!u.done&&(i=l.return)&&i.call(l)}finally{if(e)throw e.error}}this.styles[t]=a}var f=/^(?:[\d.]+(?:[a-z]+)|thin|medium|thick|inherit|initial|unset)$/,h=/^(?:none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset|inherit|initial|unset)$/;function d(t){var e,n,o,i,s={width:"",style:"",color:""};try{for(var l=r(a(this.styles[t])),u=l.next();!u.done;u=l.next()){var c=u.value;c.match(f)&&""===s.width?s.width=c:c.match(h)&&""===s.style?s.style=c:s.color=c}}catch(t){e={error:t}}finally{try{u&&!u.done&&(n=l.return)&&n.call(l)}finally{if(e)throw e.error}}try{for(var p=r(v.connect[t].children),d=p.next();!d.done;d=p.next()){var y=d.value;this.setStyle(this.childName(t,y),s[y])}}catch(t){o={error:t}}finally{try{d&&!d.done&&(i=p.return)&&i.call(p)}finally{if(o)throw o.error}}}function y(t){var e,n,o=[];try{for(var i=r(v.connect[t].children),s=i.next();!s.done;s=i.next()){var a=s.value,l=this.styles[this.childName(t,a)];l&&o.push(l)}}catch(t){e={error:t}}finally{try{s&&!s.done&&(n=i.return)&&n.call(i)}finally{if(e)throw e.error}}o.length?this.styles[t]=o.join(" "):delete this.styles[t]}var O={style:/^(?:normal|italic|oblique|inherit|initial|unset)$/,variant:new RegExp("^(?:"+["normal|none","inherit|initial|unset","common-ligatures|no-common-ligatures","discretionary-ligatures|no-discretionary-ligatures","historical-ligatures|no-historical-ligatures","contextual|no-contextual","(?:stylistic|character-variant|swash|ornaments|annotation)\\([^)]*\\)","small-caps|all-small-caps|petite-caps|all-petite-caps|unicase|titling-caps","lining-nums|oldstyle-nums|proportional-nums|tabular-nums","diagonal-fractions|stacked-fractions","ordinal|slashed-zero","jis78|jis83|jis90|jis04|simplified|traditional","full-width|proportional-width","ruby"].join("|")+")$"),weight:/^(?:normal|bold|bolder|lighter|[1-9]00|inherit|initial|unset)$/,stretch:new RegExp("^(?:"+["normal","(?:(?:ultra|extra|semi)-)?condensed","(?:(?:semi|extra|ulta)-)?expanded","inherit|initial|unset"].join("|")+")$"),size:new RegExp("^(?:"+["xx-small|x-small|small|medium|large|x-large|xx-large|larger|smaller","[d.]+%|[d.]+[a-z]+","inherit|initial|unset"].join("|")+")(?:/(?:normal|[d.+](?:%|[a-z]+)?))?$")};function M(t){var e,o,i,s,l=a(this.styles[t]),u={style:"",variant:[],weight:"",stretch:"",size:"",family:"","line-height":""};try{for(var c=r(l),p=c.next();!p.done;p=c.next()){var f=p.value;u.family=f;try{for(var h=(i=void 0,r(Object.keys(O))),d=h.next();!d.done;d=h.next()){var y=d.value;if((Array.isArray(u[y])||""===u[y])&&f.match(O[y]))if("size"===y){var M=n(f.split(/\//),2),E=M[0],b=M[1];u[y]=E,b&&(u["line-height"]=b)}else""===u.size&&(Array.isArray(u[y])?u[y].push(f):u[y]=f)}}catch(t){i={error:t}}finally{try{d&&!d.done&&(s=h.return)&&s.call(h)}finally{if(i)throw i.error}}}}catch(t){e={error:t}}finally{try{p&&!p.done&&(o=c.return)&&o.call(c)}finally{if(e)throw e.error}}!function(t,e){var n,o;try{for(var i=r(v.connect[t].children),s=i.next();!s.done;s=i.next()){var a=s.value,l=this.childName(t,a);if(Array.isArray(e[a])){var u=e[a];u.length&&(this.styles[l]=u.join(" "))}else""!==e[a]&&(this.styles[l]=e[a])}}catch(t){n={error:t}}finally{try{s&&!s.done&&(o=i.return)&&o.call(i)}finally{if(n)throw n.error}}}(t,u),delete this.styles[t]}function E(t){}var v=function(){function t(t){void 0===t&&(t=""),this.parse(t)}return Object.defineProperty(t.prototype,"cssText",{get:function(){var t,e,n=[];try{for(var o=r(Object.keys(this.styles)),i=o.next();!i.done;i=o.next()){var s=i.value,a=this.parentName(s);this.styles[a]||n.push(s+": "+this.styles[s])}}catch(e){t={error:e}}finally{try{i&&!i.done&&(e=o.return)&&e.call(o)}finally{if(t)throw t.error}}return n.join("; ")},enumerable:!1,configurable:!0}),t.prototype.set=function(e,r){for(e=this.normalizeName(e),this.setStyle(e,r),t.connect[e]&&!t.connect[e].combine&&(this.combineChildren(e),delete this.styles[e]);e.match(/-/)&&(e=this.parentName(e),t.connect[e]);)t.connect[e].combine.call(this,e)},t.prototype.get=function(t){return t=this.normalizeName(t),this.styles.hasOwnProperty(t)?this.styles[t]:""},t.prototype.setStyle=function(e,r){this.styles[e]=r,t.connect[e]&&t.connect[e].children&&t.connect[e].split.call(this,e),""===r&&delete this.styles[e]},t.prototype.combineChildren=function(e){var n,o,i=this.parentName(e);try{for(var s=r(t.connect[e].children),a=s.next();!a.done;a=s.next()){var l=a.value,u=this.childName(i,l);t.connect[u].combine.call(this,u)}}catch(t){n={error:t}}finally{try{a&&!a.done&&(o=s.return)&&o.call(s)}finally{if(n)throw n.error}}},t.prototype.parentName=function(t){var e=t.replace(/-[^-]*$/,"");return t===e?"":e},t.prototype.childName=function(e,r){return r.match(/-/)?r:(t.connect[e]&&!t.connect[e].combine&&(r+=e.replace(/.*-/,"-"),e=this.parentName(e)),e+"-"+r)},t.prototype.normalizeName=function(t){return t.replace(/[A-Z]/g,(function(t){return"-"+t.toLowerCase()}))},t.prototype.parse=function(t){void 0===t&&(t="");var e=this.constructor.pattern;this.styles={};for(var r=t.replace(e.comment,"").split(e.style);r.length>1;){var o=n(r.splice(0,3),3),i=o[0],s=o[1],a=o[2];if(i.match(/[^\s\n]/))return;this.set(s,a)}},t.pattern={style:/([-a-z]+)[\s\n]*:[\s\n]*((?:'[^']*'|"[^"]*"|\n|.)*?)[\s\n]*(?:;|$)/g,comment:/\/\*[^]*?\*\//g},t.connect={padding:{children:i,split:l,combine:u},border:{children:i,split:c,combine:p},"border-top":{children:s,split:d,combine:y},"border-right":{children:s,split:d,combine:y},"border-bottom":{children:s,split:d,combine:y},"border-left":{children:s,split:d,combine:y},"border-width":{children:i,split:l,combine:null},"border-style":{children:i,split:l,combine:null},"border-color":{children:i,split:l,combine:null},font:{children:["style","variant","weight","stretch","line-height","size","family"],split:M,combine:E}},t}();e.Styles=v},6010:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.px=e.emRounded=e.em=e.percent=e.length2em=e.MATHSPACE=e.RELUNITS=e.UNITS=e.BIGDIMEN=void 0,e.BIGDIMEN=1e6,e.UNITS={px:1,in:96,cm:96/2.54,mm:96/25.4},e.RELUNITS={em:1,ex:.431,pt:.1,pc:1.2,mu:1/18},e.MATHSPACE={veryverythinmathspace:1/18,verythinmathspace:2/18,thinmathspace:3/18,mediummathspace:4/18,thickmathspace:5/18,verythickmathspace:6/18,veryverythickmathspace:7/18,negativeveryverythinmathspace:-1/18,negativeverythinmathspace:-2/18,negativethinmathspace:-3/18,negativemediummathspace:-4/18,negativethickmathspace:-5/18,negativeverythickmathspace:-6/18,negativeveryverythickmathspace:-7/18,thin:.04,medium:.06,thick:.1,normal:1,big:2,small:1/Math.sqrt(2),infinity:e.BIGDIMEN},e.length2em=function(t,r,n,o){if(void 0===r&&(r=0),void 0===n&&(n=1),void 0===o&&(o=16),"string"!=typeof t&&(t=String(t)),""===t||null==t)return r;if(e.MATHSPACE[t])return e.MATHSPACE[t];var i=t.match(/^\s*([-+]?(?:\.\d+|\d+(?:\.\d*)?))?(pt|em|ex|mu|px|pc|in|mm|cm|%)?/);if(!i)return r;var s=parseFloat(i[1]||"1"),a=i[2];return e.UNITS.hasOwnProperty(a)?s*e.UNITS[a]/o/n:e.RELUNITS.hasOwnProperty(a)?s*e.RELUNITS[a]:"%"===a?s/100*r:s*r},e.percent=function(t){return(100*t).toFixed(1).replace(/\.?0+$/,"")+"%"},e.em=function(t){return Math.abs(t)<.001?"0":t.toFixed(3).replace(/\.?0+$/,"")+"em"},e.emRounded=function(t,e){return void 0===e&&(e=16),t=(Math.round(t*e)+.05)/e,Math.abs(t)<.001?"0em":t.toFixed(3).replace(/\.?0+$/,"")+"em"},e.px=function(t,r,n){return void 0===r&&(r=-e.BIGDIMEN),void 0===n&&(n=16),t*=n,r&&t0)&&!(n=i.next()).done;)s.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return s},n=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=s.next()).done;)r.push(n.value)}catch(t){a={error:t}}finally{try{n&&!n.done&&(i=s.return)&&i.call(s)}finally{if(a)throw a.error}}return r};Object.defineProperty(e,"__esModule",{value:!0}),e.AsciiMath=void 0;var o=i(309),l=i(406),u=i(77),h=i(577),p=function(t){function e(i){var n=this,a=r(u.separateOptions(i,h.FindAsciiMath.OPTIONS,e.OPTIONS),3),s=a[1],o=a[2];return(n=t.call(this,o)||this).findAsciiMath=n.options.FindAsciiMath||new h.FindAsciiMath(s),n}return a(e,t),e.prototype.compile=function(t,e){return l.LegacyAsciiMath.Compile(t.math,t.display)},e.prototype.findMath=function(t){return this.findAsciiMath.findMath(t)},e.NAME="AsciiMath",e.OPTIONS=s(s({},o.AbstractInputJax.OPTIONS),{FindAsciiMath:null}),e}(o.AbstractInputJax);e.AsciiMath=p},577:function(t,e,i){"use strict";var n,a=this&&this.__extends||(n=function(t,e){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[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 i(){this.constructor=t}n(t,e),t.prototype=null===e?Object.create(e):(i.prototype=e.prototype,new i)}),s=this&&this.__read||function(t,e){var i="function"==typeof Symbol&&t[Symbol.iterator];if(!i)return t;var n,a,s=i.call(t),r=[];try{for(;(void 0===e||e-- >0)&&!(n=s.next()).done;)r.push(n.value)}catch(t){a={error:t}}finally{try{n&&!n.done&&(i=s.return)&&i.call(s)}finally{if(a)throw a.error}}return r};Object.defineProperty(e,"__esModule",{value:!0}),e.FindAsciiMath=void 0;var r=i(649),o=i(720),l=i(769),u=function(t){function e(e){var i=t.call(this,e)||this;return i.getPatterns(),i}return a(e,t),e.prototype.getPatterns=function(){var t=this,e=this.options,i=[];this.end={},e.delimiters.forEach((function(e){return t.addPattern(i,e,!1)})),this.start=new RegExp(i.join("|"),"g"),this.hasPatterns=i.length>0},e.prototype.addPattern=function(t,e,i){var n=s(e,2),a=n[0],r=n[1];t.push(o.quotePattern(a)),this.end[a]=[r,i,new RegExp(o.quotePattern(r),"g")]},e.prototype.findEnd=function(t,e,i,n){var a=s(n,3),r=a[1],o=a[2],u=o.lastIndex=i.index+i[0].length,h=o.exec(t);return h?l.protoItem(i[0],t.substr(u,h.index-u),h[0],e,i.index,h.index+h[0].length,r):null},e.prototype.findMathInString=function(t,e,i){var n,a;for(this.start.lastIndex=0;n=this.start.exec(i);)(a=this.findEnd(i,e,n,this.end[n[0]]))&&(t.push(a),this.start.lastIndex=a.end.n)},e.prototype.findMath=function(t){var e=[];if(this.hasPatterns)for(var i=0,n=t.length;i1&&(t=2===arguments.length&&"function"!=typeof arguments[0]&&arguments[0]instanceof Object&&"number"==typeof arguments[1]?[].slice.call(t,e):[].slice.call(arguments,0)),t instanceof Array&&1===t.length&&(t=t[0]),"function"==typeof t)return t.execute===i.prototype.execute?t:i({hook:t});if(t instanceof Array){if("string"==typeof t[0]&&t[1]instanceof Object&&"function"==typeof t[1][t[0]])return i({hook:t[1][t[0]],object:t[1],data:t.slice(2)});if("function"==typeof t[0])return i({hook:t[0],data:t.slice(1)});if("function"==typeof t[1])return i({hook:t[1],object:t[0],data:t.slice(2)})}else{if("string"==typeof t)return s&&s(),i({hook:a,data:[t]});if(t instanceof Object)return i(t);if(void 0===t)return i({})}throw Error("Can't make callback from given data")},o=function(t,e){(t=r(t)).called||(c(t,e),e.pending++)},h=function(){var t=this.signal;delete this.signal,this.execute=this.oldExecute,delete this.oldExecute;var e=this.execute.apply(this,arguments);if(n(e)&&!e.called)c(e,t);else for(var i=0,a=t.length;i0&&e=0;t--)this.hooks.splice(t,1);this.remove=[]}}),f=e.Object.Subclass({Init:function(){this.pending=this.running=0,this.queue=[],this.Push.apply(this,arguments)},Push:function(){for(var t,e=0,i=arguments.length;e=this.timeout?(t(this.STATUS.ERROR),1):0},file:function(t,i){i<0?e.Ajax.loadTimeout(t):e.Ajax.loadComplete(t)},execute:function(){this.hook.call(this.object,this,this.data[0],this.data[1])},checkSafari2:function(t,e,i){t.time(i)||(p.styleSheets.length>e&&p.styleSheets[e].cssRules&&p.styleSheets[e].cssRules.length?i(t.STATUS.OK):setTimeout(t,t.delay))},checkLength:function(t,i,n){if(!t.time(n)){var a=0,s=i.sheet||i.styleSheet;try{(s.cssRules||s.rules||[]).length>0&&(a=1)}catch(t){(t.message.match(/protected variable|restricted URI/)||t.message.match(/Security error/))&&(a=1)}a?setTimeout(e.Callback([n,t.STATUS.OK]),0):setTimeout(t,t.delay)}}},loadComplete:function(t){t=this.fileURL(t);var i=this.loading[t];return i&&!i.preloaded?(e.Message.Clear(i.message),i.timeout&&clearTimeout(i.timeout),i.script&&(0===a.length&&setTimeout(s,0),a.push(i.script)),this.loaded[t]=i.status,delete this.loading[t],this.addHook(t,i.callback)):(i&&delete this.loading[t],this.loaded[t]=this.STATUS.OK,i={status:this.STATUS.OK}),this.loadHooks[t]?this.loadHooks[t].Execute(i.status):null},loadTimeout:function(t){this.loading[t].timeout&&clearTimeout(this.loading[t].timeout),this.loading[t].status=this.STATUS.ERROR,this.loadError(t),this.loadComplete(t)},loadError:function(t){e.Message.Set(["LoadFailed","File failed to load: %1",t],null,2e3),e.Hub.signal.Post(["file load error",t])},Styles:function(t,i){var n=this.StyleString(t);if(""===n)(i=e.Callback(i))();else{var a=p.createElement("style");a.type="text/css",this.head=(this.head,null),this.head.appendChild(a),a.styleSheet&&void 0!==a.styleSheet.cssText?a.styleSheet.cssText=n:a.appendChild(p.createTextNode(n)),i=this.timer.create.call(this,i,a)}return i},StyleString:function(t){if("string"==typeof t)return t;var e,i,n="";for(e in t)if(t.hasOwnProperty(e))if("string"==typeof t[e])n+=e+" {"+t[e]+"}\n";else if(t[e]instanceof Array)for(var a=0;a="0"&&r<="9")s[n]=e[s[n]-1],"number"==typeof s[n]&&(s[n]=this.number(s[n]));else if("{"===r)if((r=s[n].substr(1))>="0"&&r<="9")s[n]=e[s[n].substr(1,s[n].length-2)-1],"number"==typeof s[n]&&(s[n]=this.number(s[n]));else{var o=s[n].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);if(o)if("plural"===o[1]){var l=e[o[2]-1];if(void 0===l)s[n]="???";else{l=this.plural(l)-1;var u=o[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uefef").split(/\|/);l>=0&&l=3?i.push([s[0],s[1],this.processSnippet(t,s[2])]):i.push(e[n])}else i.push(e[n]);return i},markdownPattern:/(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,processMarkdown:function(t,e,i){for(var n,a=[],s=t.split(this.markdownPattern),r=s[0],o=1,l=s.length;o0||this.Get("scriptlevel")>0)&&n>=0?"":this.TEXSPACELENGTH[Math.abs(n)]},TEXSPACELENGTH:["",t.LENGTH.THINMATHSPACE,t.LENGTH.MEDIUMMATHSPACE,t.LENGTH.THICKMATHSPACE],TEXSPACE:[[0,-1,2,3,0,0,0,1],[-1,-1,0,3,0,0,0,1],[2,2,0,0,2,0,0,2],[3,3,0,0,3,0,0,3],[0,0,0,0,0,0,0,0],[0,-1,2,3,0,0,0,1],[1,1,0,1,1,1,1,1],[1,-1,2,3,1,0,1,1]],autoDefault:function(t){return""},isSpacelike:function(){return!1},isEmbellished:function(){return!1},Core:function(){return this},CoreMO:function(){return this},childIndex:function(t){if(null!=t)for(var e=0,i=this.data.length;e=55296&&i.charCodeAt(0)<56320?t.VARIANT.ITALIC:t.VARIANT.NORMAL}return""},setTeXclass:function(e){this.getPrevClass(e);var i=this.data.join("");return i.length>1&&i.match(/^[a-z][a-z0-9]*$/i)&&this.texClass===t.TEXCLASS.ORD&&(this.texClass=t.TEXCLASS.OP,this.autoOP=!0),this}}),t.mn=t.mbase.Subclass({type:"mn",isToken:!0,texClass:t.TEXCLASS.ORD,defaults:{mathvariant:t.INHERIT,mathsize:t.INHERIT,mathbackground:t.INHERIT,mathcolor:t.INHERIT,dir:t.INHERIT}}),t.mo=t.mbase.Subclass({type:"mo",isToken:!0,defaults:{mathvariant:t.INHERIT,mathsize:t.INHERIT,mathbackground:t.INHERIT,mathcolor:t.INHERIT,dir:t.INHERIT,form:t.AUTO,fence:t.AUTO,separator:t.AUTO,lspace:t.AUTO,rspace:t.AUTO,stretchy:t.AUTO,symmetric:t.AUTO,maxsize:t.AUTO,minsize:t.AUTO,largeop:t.AUTO,movablelimits:t.AUTO,accent:t.AUTO,linebreak:t.LINEBREAK.AUTO,lineleading:t.INHERIT,linebreakstyle:t.AUTO,linebreakmultchar:t.INHERIT,indentalign:t.INHERIT,indentshift:t.INHERIT,indenttarget:t.INHERIT,indentalignfirst:t.INHERIT,indentshiftfirst:t.INHERIT,indentalignlast:t.INHERIT,indentshiftlast:t.INHERIT,texClass:t.AUTO},defaultDef:{form:t.FORM.INFIX,fence:!1,separator:!1,lspace:t.LENGTH.THICKMATHSPACE,rspace:t.LENGTH.THICKMATHSPACE,stretchy:!1,symmetric:!1,maxsize:t.SIZE.INFINITY,minsize:"0em",largeop:!1,movablelimits:!1,accent:!1,linebreak:t.LINEBREAK.AUTO,lineleading:"1ex",linebreakstyle:"before",indentalign:t.INDENTALIGN.AUTO,indentshift:"0",indenttarget:"",indentalignfirst:t.INDENTALIGN.INDENTALIGN,indentshiftfirst:t.INDENTSHIFT.INDENTSHIFT,indentalignlast:t.INDENTALIGN.INDENTALIGN,indentshiftlast:t.INDENTSHIFT.INDENTSHIFT,texClass:t.TEXCLASS.REL},SPACE_ATTR:{lspace:1,rspace:2,form:4},useMMLspacing:7,autoDefault:function(e,i){var n=this.def;if(!n){if("form"===e)return this.useMMLspacing&=~this.SPACE_ATTR.form,this.getForm();for(var a=this.data.join(""),s=[this.Get("form"),t.FORM.INFIX,t.FORM.POSTFIX,t.FORM.PREFIX],r=0,o=s.length;r=55296&&i<56320&&(i=(i-55296<<10)+(e.charCodeAt(1)-56320)+65536);for(var n=0,a=this.RANGES.length;n=0;t--)if(this.data[0]&&!this.data[t].isSpacelike())return this.data[t];return null},Core:function(){return this.isEmbellished()&&void 0!==this.core?this.data[this.core]:this},CoreMO:function(){return this.isEmbellished()&&void 0!==this.core?this.data[this.core].CoreMO():this},toString:function(){return this.inferred?"["+this.data.join(",")+"]":this.SUPER(arguments).toString.call(this)},setTeXclass:function(e){var i,n=this.data.length;if(!this.open&&!this.close||e&&e.fnOP){for(i=0;i0)&&e++,e},adjustChild_texprimestyle:function(t){return t==this.den||this.Get("texprimestyle")},setTeXclass:t.mbase.setSeparateTeXclasses}),t.msqrt=t.mbase.Subclass({type:"msqrt",inferRow:!0,linebreakContainer:!0,texClass:t.TEXCLASS.ORD,setTeXclass:t.mbase.setSeparateTeXclasses,adjustChild_texprimestyle:function(t){return!0}}),t.mroot=t.mbase.Subclass({type:"mroot",linebreakContainer:!0,texClass:t.TEXCLASS.ORD,adjustChild_displaystyle:function(t){return 1!==t&&this.Get("displaystyle")},adjustChild_scriptlevel:function(t){var e=this.Get("scriptlevel");return 1===t&&(e+=2),e},adjustChild_texprimestyle:function(t){return 0===t||this.Get("texprimestyle")},setTeXclass:t.mbase.setSeparateTeXclasses}),t.mstyle=t.mbase.Subclass({type:"mstyle",isSpacelike:t.mbase.childrenSpacelike,isEmbellished:t.mbase.childEmbellished,Core:t.mbase.childCore,CoreMO:t.mbase.childCoreMO,inferRow:!0,defaults:{scriptlevel:t.INHERIT,displaystyle:t.INHERIT,scriptsizemultiplier:Math.sqrt(.5),scriptminsize:"8pt",mathbackground:t.INHERIT,mathcolor:t.INHERIT,dir:t.INHERIT,infixlinebreakstyle:t.LINEBREAKSTYLE.BEFORE,decimalseparator:"."},adjustChild_scriptlevel:function(t){var e=this.scriptlevel;if(null==e)e=this.Get("scriptlevel");else if(String(e).match(/^ *[-+]/)){e=this.Get("scriptlevel",null,!0)+parseInt(e)}return e},inheritFromMe:!0,noInherit:{mpadded:{width:!0,height:!0,depth:!0,lspace:!0,voffset:!0},mtable:{width:!0,height:!0,depth:!0,align:!0}},getRemoved:{fontfamily:"fontFamily",fontweight:"fontWeight",fontstyle:"fontStyle",fontsize:"fontSize"},setTeXclass:t.mbase.setChildTeXclass}),t.merror=t.mbase.Subclass({type:"merror",inferRow:!0,linebreakContainer:!0,texClass:t.TEXCLASS.ORD}),t.mpadded=t.mbase.Subclass({type:"mpadded",inferRow:!0,isSpacelike:t.mbase.childrenSpacelike,isEmbellished:t.mbase.childEmbellished,Core:t.mbase.childCore,CoreMO:t.mbase.childCoreMO,defaults:{mathbackground:t.INHERIT,mathcolor:t.INHERIT,width:"",height:"",depth:"",lspace:0,voffset:0},setTeXclass:t.mbase.setChildTeXclass}),t.mphantom=t.mbase.Subclass({type:"mphantom",texClass:t.TEXCLASS.ORD,inferRow:!0,isSpacelike:t.mbase.childrenSpacelike,isEmbellished:t.mbase.childEmbellished,Core:t.mbase.childCore,CoreMO:t.mbase.childCoreMO,setTeXclass:t.mbase.setChildTeXclass}),t.mfenced=t.mbase.Subclass({type:"mfenced",defaults:{mathbackground:t.INHERIT,mathcolor:t.INHERIT,open:"(",close:")",separators:","},addFakeNodes:function(){var e=this.getValues("open","close","separators");if(e.open=e.open.replace(/[ \t\n\r]/g,""),e.close=e.close.replace(/[ \t\n\r]/g,""),e.separators=e.separators.replace(/[ \t\n\r]/g,""),""!==e.open&&(this.SetData("open",t.mo(e.open).With({fence:!0,form:t.FORM.PREFIX,texClass:t.TEXCLASS.OPEN})),this.data.open.useMMLspacing=0),""!==e.separators){for(;e.separators.length0)&&this.Get("displaystyle")},adjustChild_scriptlevel:function(t){var e=this.Get("scriptlevel");return t>0&&e++,e},adjustChild_texprimestyle:function(t){return t===this.sub||this.Get("texprimestyle")},setTeXclass:t.mbase.setBaseTeXclasses}),t.msub=t.msubsup.Subclass({type:"msub"}),t.msup=t.msubsup.Subclass({type:"msup",sub:2,sup:1}),t.mmultiscripts=t.msubsup.Subclass({type:"mmultiscripts",adjustChild_texprimestyle:function(t){return t%2==1||this.Get("texprimestyle")}}),t.mprescripts=t.mbase.Subclass({type:"mprescripts"}),t.none=t.mbase.Subclass({type:"none"}),t.munderover=t.mbase.Subclass({type:"munderover",base:0,under:1,over:2,sub:1,sup:2,ACCENTS:["","accentunder","accent"],linebreakContainer:!0,isEmbellished:t.mbase.childEmbellished,Core:t.mbase.childCore,CoreMO:t.mbase.childCoreMO,defaults:{mathbackground:t.INHERIT,mathcolor:t.INHERIT,accent:t.AUTO,accentunder:t.AUTO,align:t.ALIGN.CENTER,texClass:t.AUTO,subscriptshift:"",superscriptshift:""},autoDefault:function(e){return"texClass"===e?this.isEmbellished()?this.CoreMO().Get(e):t.TEXCLASS.ORD:"accent"===e&&this.data[this.over]?this.data[this.over].CoreMO().Get("accent"):!("accentunder"!==e||!this.data[this.under])&&this.data[this.under].CoreMO().Get("accent")},adjustChild_displaystyle:function(t){return!(t>0)&&this.Get("displaystyle")},adjustChild_scriptlevel:function(t){var e=this.Get("scriptlevel"),i=this.data[this.base]&&!this.Get("displaystyle")&&this.data[this.base].CoreMO().Get("movablelimits");return t!=this.under||!i&&this.Get("accentunder")||e++,t!=this.over||!i&&this.Get("accent")||e++,e},adjustChild_texprimestyle:function(t){return!(t!==this.base||!this.data[this.over])||this.Get("texprimestyle")},setTeXclass:t.mbase.setBaseTeXclasses}),t.munder=t.munderover.Subclass({type:"munder"}),t.mover=t.munderover.Subclass({type:"mover",over:1,under:2,sup:1,sub:2,ACCENTS:["","accent","accentunder"]}),t.mtable=t.mbase.Subclass({type:"mtable",defaults:{mathbackground:t.INHERIT,mathcolor:t.INHERIT,align:t.ALIGN.AXIS,rowalign:t.ALIGN.BASELINE,columnalign:t.ALIGN.CENTER,groupalign:"{left}",alignmentscope:!0,columnwidth:t.WIDTH.AUTO,width:t.WIDTH.AUTO,rowspacing:"1ex",columnspacing:".8em",rowlines:t.LINES.NONE,columnlines:t.LINES.NONE,frame:t.LINES.NONE,framespacing:"0.4em 0.5ex",equalrows:!1,equalcolumns:!1,displaystyle:!1,side:t.SIDE.RIGHT,minlabelspacing:"0.8em",texClass:t.TEXCLASS.ORD,useHeight:1},adjustChild_displaystyle:function(){return null!=this.displaystyle?this.displaystyle:this.defaults.displaystyle},inheritFromMe:!0,noInherit:{mover:{align:!0},munder:{align:!0},munderover:{align:!0},mtable:{align:!0,rowalign:!0,columnalign:!0,groupalign:!0,alignmentscope:!0,columnwidth:!0,width:!0,rowspacing:!0,columnspacing:!0,rowlines:!0,columnlines:!0,frame:!0,framespacing:!0,equalrows:!0,equalcolumns:!0,displaystyle:!0,side:!0,minlabelspacing:!0,texClass:!0,useHeight:1}},linebreakContainer:!0,Append:function(){for(var e=0,i=arguments.length;e>10),56320+(1023&t)))}}),t.xml=t.mbase.Subclass({type:"xml",Init:function(){return this.div=document.createElement("div"),this.SUPER(arguments).Init.apply(this,arguments)},Append:function(){for(var t=0,e=arguments.length;t":i.REL,"?":[1,1,e.CLOSE],"\\":i.ORD,"^":i.ORD11,_:i.ORD11,"|":[2,2,e.ORD,{fence:!0,stretchy:!0,symmetric:!0}],"#":i.ORD,$:i.ORD,".":[0,3,e.PUNCT,{separator:!0}],"\u02b9":i.ORD,"\u0300":i.ACCENT,"\u0301":i.ACCENT,"\u0303":i.WIDEACCENT,"\u0304":i.ACCENT,"\u0306":i.ACCENT,"\u0307":i.ACCENT,"\u0308":i.ACCENT,"\u030c":i.ACCENT,"\u0332":i.WIDEACCENT,"\u0338":i.REL4,"\u2015":[0,0,e.ORD,{stretchy:!0}],"\u2017":[0,0,e.ORD,{stretchy:!0}],"\u2020":i.BIN3,"\u2021":i.BIN3,"\u20d7":i.ACCENT,"\u2111":i.ORD,"\u2113":i.ORD,"\u2118":i.ORD,"\u211c":i.ORD,"\u2205":i.ORD,"\u221e":i.ORD,"\u2305":i.BIN3,"\u2306":i.BIN3,"\u2322":i.REL4,"\u2323":i.REL4,"\u2329":i.OPEN,"\u232a":i.CLOSE,"\u23aa":i.ORD,"\u23af":[0,0,e.ORD,{stretchy:!0}],"\u23b0":i.OPEN,"\u23b1":i.CLOSE,"\u2500":i.ORD,"\u25ef":i.BIN3,"\u2660":i.ORD,"\u2661":i.ORD,"\u2662":i.ORD,"\u2663":i.ORD,"\u3008":i.OPEN,"\u3009":i.CLOSE,"\ufe37":i.WIDEACCENT,"\ufe38":i.WIDEACCENT}}},{OPTYPES:i});var n=t.mo.prototype.OPTABLE;n.infix["^"]=i.WIDEREL,n.infix._=i.WIDEREL,n.prefix["\u2223"]=i.OPEN,n.prefix["\u2225"]=i.OPEN,n.postfix["\u2223"]=i.CLOSE,n.postfix["\u2225"]=i.CLOSE}(MathJax.ElementJax.mml),MathJax.ElementJax.mml.loadComplete("jax.js")},315:function(){MathJax.InputJax.AsciiMath=MathJax.InputJax({id:"AsciiMath",version:"2.7.2",directory:MathJax.InputJax.directory+"/AsciiMath",extensionDir:MathJax.InputJax.extensionDir+"/AsciiMath",config:{fixphi:!0,useMathMLspacing:!0,displaystyle:!0,decimalsign:"."}}),MathJax.InputJax.AsciiMath.Register("math/asciimath"),MathJax.InputJax.AsciiMath.loadComplete("config.js")},247:function(){var t,e;!function(t){var e,i=MathJax.Object.Subclass({firstChild:null,lastChild:null,Init:function(){this.childNodes=[]},appendChild:function(t){return t.parent&&t.parent.removeChild(t),this.lastChild&&(this.lastChild.nextSibling=t),this.firstChild||(this.firstChild=t),this.childNodes.push(t),t.parent=this,this.lastChild=t,t},removeChild:function(t){for(var e=0,i=this.childNodes.length;e=n-1&&(this.lastChild=t),this.childNodes[i]=t,t.nextSibling=e.nextSibling,e.nextSibling=e.parent=null,e},hasChildNodes:function(t){return this.childNodes.length>0},toString:function(){return"{"+this.childNodes.join("")+"}"}}),n={getElementById:!0,createElementNS:function(i,n){var a=e[n]();return"mo"===n&&t.config.useMathMLspacing&&(a.useMMLspacing=128),a},createTextNode:function(t){return e.chars(t).With({nodeValue:t})},createDocumentFragment:function(){return i()}},a={appName:"MathJax"},s="blue",r=!0,o=!0,l=".",u="Microsoft"==a.appName.slice(0,9);function h(t){return u?n.createElement(t):n.createElementNS("http://www.w3.org/1999/xhtml",t)}var p="http://www.w3.org/1998/Math/MathML";function c(t){return u?n.createElement("m:"+t):n.createElementNS(p,t)}function d(t,e){var i;return i=u?n.createElement("m:"+t):n.createElementNS(p,t),e&&i.appendChild(e),i}var m=["\ud835\udc9c","\u212c","\ud835\udc9e","\ud835\udc9f","\u2130","\u2131","\ud835\udca2","\u210b","\u2110","\ud835\udca5","\ud835\udca6","\u2112","\u2133","\ud835\udca9","\ud835\udcaa","\ud835\udcab","\ud835\udcac","\u211b","\ud835\udcae","\ud835\udcaf","\ud835\udcb0","\ud835\udcb1","\ud835\udcb2","\ud835\udcb3","\ud835\udcb4","\ud835\udcb5","\ud835\udcb6","\ud835\udcb7","\ud835\udcb8","\ud835\udcb9","\u212f","\ud835\udcbb","\u210a","\ud835\udcbd","\ud835\udcbe","\ud835\udcbf","\ud835\udcc0","\ud835\udcc1","\ud835\udcc2","\ud835\udcc3","\u2134","\ud835\udcc5","\ud835\udcc6","\ud835\udcc7","\ud835\udcc8","\ud835\udcc9","\ud835\udcca","\ud835\udccb","\ud835\udccc","\ud835\udccd","\ud835\udcce","\ud835\udccf"],f=["\ud835\udd04","\ud835\udd05","\u212d","\ud835\udd07","\ud835\udd08","\ud835\udd09","\ud835\udd0a","\u210c","\u2111","\ud835\udd0d","\ud835\udd0e","\ud835\udd0f","\ud835\udd10","\ud835\udd11","\ud835\udd12","\ud835\udd13","\ud835\udd14","\u211c","\ud835\udd16","\ud835\udd17","\ud835\udd18","\ud835\udd19","\ud835\udd1a","\ud835\udd1b","\ud835\udd1c","\u2128","\ud835\udd1e","\ud835\udd1f","\ud835\udd20","\ud835\udd21","\ud835\udd22","\ud835\udd23","\ud835\udd24","\ud835\udd25","\ud835\udd26","\ud835\udd27","\ud835\udd28","\ud835\udd29","\ud835\udd2a","\ud835\udd2b","\ud835\udd2c","\ud835\udd2d","\ud835\udd2e","\ud835\udd2f","\ud835\udd30","\ud835\udd31","\ud835\udd32","\ud835\udd33","\ud835\udd34","\ud835\udd35","\ud835\udd36","\ud835\udd37"],g=["\ud835\udd38","\ud835\udd39","\u2102","\ud835\udd3b","\ud835\udd3c","\ud835\udd3d","\ud835\udd3e","\u210d","\ud835\udd40","\ud835\udd41","\ud835\udd42","\ud835\udd43","\ud835\udd44","\u2115","\ud835\udd46","\u2119","\u211a","\u211d","\ud835\udd4a","\ud835\udd4b","\ud835\udd4c","\ud835\udd4d","\ud835\udd4e","\ud835\udd4f","\ud835\udd50","\u2124","\ud835\udd52","\ud835\udd53","\ud835\udd54","\ud835\udd55","\ud835\udd56","\ud835\udd57","\ud835\udd58","\ud835\udd59","\ud835\udd5a","\ud835\udd5b","\ud835\udd5c","\ud835\udd5d","\ud835\udd5e","\ud835\udd5f","\ud835\udd60","\ud835\udd61","\ud835\udd62","\ud835\udd63","\ud835\udd64","\ud835\udd65","\ud835\udd66","\ud835\udd67","\ud835\udd68","\ud835\udd69","\ud835\udd6a","\ud835\udd6b"],y=8,E={input:'"',tag:"mtext",output:"mbox",tex:null,ttype:10},x=[{input:"alpha",tag:"mi",output:"\u03b1",tex:null,ttype:0},{input:"beta",tag:"mi",output:"\u03b2",tex:null,ttype:0},{input:"chi",tag:"mi",output:"\u03c7",tex:null,ttype:0},{input:"delta",tag:"mi",output:"\u03b4",tex:null,ttype:0},{input:"Delta",tag:"mo",output:"\u0394",tex:null,ttype:0},{input:"epsi",tag:"mi",output:"\u03b5",tex:"epsilon",ttype:0},{input:"varepsilon",tag:"mi",output:"\u025b",tex:null,ttype:0},{input:"eta",tag:"mi",output:"\u03b7",tex:null,ttype:0},{input:"gamma",tag:"mi",output:"\u03b3",tex:null,ttype:0},{input:"Gamma",tag:"mo",output:"\u0393",tex:null,ttype:0},{input:"iota",tag:"mi",output:"\u03b9",tex:null,ttype:0},{input:"kappa",tag:"mi",output:"\u03ba",tex:null,ttype:0},{input:"lambda",tag:"mi",output:"\u03bb",tex:null,ttype:0},{input:"Lambda",tag:"mo",output:"\u039b",tex:null,ttype:0},{input:"lamda",tag:"mi",output:"\u03bb",tex:null,ttype:0},{input:"Lamda",tag:"mo",output:"\u039b",tex:null,ttype:0},{input:"mu",tag:"mi",output:"\u03bc",tex:null,ttype:0},{input:"nu",tag:"mi",output:"\u03bd",tex:null,ttype:0},{input:"omega",tag:"mi",output:"\u03c9",tex:null,ttype:0},{input:"Omega",tag:"mo",output:"\u03a9",tex:null,ttype:0},{input:"phi",tag:"mi",output:"\u03d5",tex:null,ttype:0},{input:"varphi",tag:"mi",output:"\u03c6",tex:null,ttype:0},{input:"Phi",tag:"mo",output:"\u03a6",tex:null,ttype:0},{input:"pi",tag:"mi",output:"\u03c0",tex:null,ttype:0},{input:"Pi",tag:"mo",output:"\u03a0",tex:null,ttype:0},{input:"psi",tag:"mi",output:"\u03c8",tex:null,ttype:0},{input:"Psi",tag:"mi",output:"\u03a8",tex:null,ttype:0},{input:"rho",tag:"mi",output:"\u03c1",tex:null,ttype:0},{input:"sigma",tag:"mi",output:"\u03c3",tex:null,ttype:0},{input:"Sigma",tag:"mo",output:"\u03a3",tex:null,ttype:0},{input:"tau",tag:"mi",output:"\u03c4",tex:null,ttype:0},{input:"theta",tag:"mi",output:"\u03b8",tex:null,ttype:0},{input:"vartheta",tag:"mi",output:"\u03d1",tex:null,ttype:0},{input:"Theta",tag:"mo",output:"\u0398",tex:null,ttype:0},{input:"upsilon",tag:"mi",output:"\u03c5",tex:null,ttype:0},{input:"xi",tag:"mi",output:"\u03be",tex:null,ttype:0},{input:"Xi",tag:"mo",output:"\u039e",tex:null,ttype:0},{input:"zeta",tag:"mi",output:"\u03b6",tex:null,ttype:0},{input:"*",tag:"mo",output:"\u22c5",tex:"cdot",ttype:0},{input:"**",tag:"mo",output:"\u2217",tex:"ast",ttype:0},{input:"***",tag:"mo",output:"\u22c6",tex:"star",ttype:0},{input:"//",tag:"mo",output:"/",tex:null,ttype:0},{input:"\\\\",tag:"mo",output:"\\",tex:"backslash",ttype:0},{input:"setminus",tag:"mo",output:"\\",tex:null,ttype:0},{input:"xx",tag:"mo",output:"\xd7",tex:"times",ttype:0},{input:"|><",tag:"mo",output:"\u22c9",tex:"ltimes",ttype:0},{input:"><|",tag:"mo",output:"\u22ca",tex:"rtimes",ttype:0},{input:"|><|",tag:"mo",output:"\u22c8",tex:"bowtie",ttype:0},{input:"-:",tag:"mo",output:"\xf7",tex:"div",ttype:0},{input:"divide",tag:"mo",output:"-:",tex:null,ttype:y},{input:"@",tag:"mo",output:"\u2218",tex:"circ",ttype:0},{input:"o+",tag:"mo",output:"\u2295",tex:"oplus",ttype:0},{input:"ox",tag:"mo",output:"\u2297",tex:"otimes",ttype:0},{input:"o.",tag:"mo",output:"\u2299",tex:"odot",ttype:0},{input:"sum",tag:"mo",output:"\u2211",tex:null,ttype:7},{input:"prod",tag:"mo",output:"\u220f",tex:null,ttype:7},{input:"^^",tag:"mo",output:"\u2227",tex:"wedge",ttype:0},{input:"^^^",tag:"mo",output:"\u22c0",tex:"bigwedge",ttype:7},{input:"vv",tag:"mo",output:"\u2228",tex:"vee",ttype:0},{input:"vvv",tag:"mo",output:"\u22c1",tex:"bigvee",ttype:7},{input:"nn",tag:"mo",output:"\u2229",tex:"cap",ttype:0},{input:"nnn",tag:"mo",output:"\u22c2",tex:"bigcap",ttype:7},{input:"uu",tag:"mo",output:"\u222a",tex:"cup",ttype:0},{input:"uuu",tag:"mo",output:"\u22c3",tex:"bigcup",ttype:7},{input:"!=",tag:"mo",output:"\u2260",tex:"ne",ttype:0},{input:":=",tag:"mo",output:":=",tex:null,ttype:0},{input:"lt",tag:"mo",output:"<",tex:null,ttype:0},{input:"<=",tag:"mo",output:"\u2264",tex:"le",ttype:0},{input:"lt=",tag:"mo",output:"\u2264",tex:"leq",ttype:0},{input:"gt",tag:"mo",output:">",tex:null,ttype:0},{input:">=",tag:"mo",output:"\u2265",tex:"ge",ttype:0},{input:"gt=",tag:"mo",output:"\u2265",tex:"geq",ttype:0},{input:"-<",tag:"mo",output:"\u227a",tex:"prec",ttype:0},{input:"-lt",tag:"mo",output:"\u227a",tex:null,ttype:0},{input:">-",tag:"mo",output:"\u227b",tex:"succ",ttype:0},{input:"-<=",tag:"mo",output:"\u2aaf",tex:"preceq",ttype:0},{input:">-=",tag:"mo",output:"\u2ab0",tex:"succeq",ttype:0},{input:"in",tag:"mo",output:"\u2208",tex:null,ttype:0},{input:"!in",tag:"mo",output:"\u2209",tex:"notin",ttype:0},{input:"sub",tag:"mo",output:"\u2282",tex:"subset",ttype:0},{input:"sup",tag:"mo",output:"\u2283",tex:"supset",ttype:0},{input:"sube",tag:"mo",output:"\u2286",tex:"subseteq",ttype:0},{input:"supe",tag:"mo",output:"\u2287",tex:"supseteq",ttype:0},{input:"-=",tag:"mo",output:"\u2261",tex:"equiv",ttype:0},{input:"~=",tag:"mo",output:"\u2245",tex:"cong",ttype:0},{input:"~~",tag:"mo",output:"\u2248",tex:"approx",ttype:0},{input:"~",tag:"mo",output:"\u223c",tex:"sim",ttype:0},{input:"prop",tag:"mo",output:"\u221d",tex:"propto",ttype:0},{input:"and",tag:"mtext",output:"and",tex:null,ttype:6},{input:"or",tag:"mtext",output:"or",tex:null,ttype:6},{input:"not",tag:"mo",output:"\xac",tex:"neg",ttype:0},{input:"=>",tag:"mo",output:"\u21d2",tex:"implies",ttype:0},{input:"if",tag:"mo",output:"if",tex:null,ttype:6},{input:"<=>",tag:"mo",output:"\u21d4",tex:"iff",ttype:0},{input:"AA",tag:"mo",output:"\u2200",tex:"forall",ttype:0},{input:"EE",tag:"mo",output:"\u2203",tex:"exists",ttype:0},{input:"_|_",tag:"mo",output:"\u22a5",tex:"bot",ttype:0},{input:"TT",tag:"mo",output:"\u22a4",tex:"top",ttype:0},{input:"|--",tag:"mo",output:"\u22a2",tex:"vdash",ttype:0},{input:"|==",tag:"mo",output:"\u22a8",tex:"models",ttype:0},{input:"(",tag:"mo",output:"(",tex:"left(",ttype:4},{input:")",tag:"mo",output:")",tex:"right)",ttype:5},{input:"[",tag:"mo",output:"[",tex:"left[",ttype:4},{input:"]",tag:"mo",output:"]",tex:"right]",ttype:5},{input:"{",tag:"mo",output:"{",tex:null,ttype:4},{input:"}",tag:"mo",output:"}",tex:null,ttype:5},{input:"|",tag:"mo",output:"|",tex:null,ttype:9},{input:":|:",tag:"mo",output:"|",tex:null,ttype:0},{input:"|:",tag:"mo",output:"|",tex:null,ttype:4},{input:":|",tag:"mo",output:"|",tex:null,ttype:5},{input:"(:",tag:"mo",output:"\u2329",tex:"langle",ttype:4},{input:":)",tag:"mo",output:"\u232a",tex:"rangle",ttype:5},{input:"<<",tag:"mo",output:"\u2329",tex:null,ttype:4},{input:">>",tag:"mo",output:"\u232a",tex:null,ttype:5},{input:"{:",tag:"mo",output:"{:",tex:null,ttype:4,invisible:!0},{input:":}",tag:"mo",output:":}",tex:null,ttype:5,invisible:!0},{input:"int",tag:"mo",output:"\u222b",tex:null,ttype:0},{input:"dx",tag:"mi",output:"{:d x:}",tex:null,ttype:y},{input:"dy",tag:"mi",output:"{:d y:}",tex:null,ttype:y},{input:"dz",tag:"mi",output:"{:d z:}",tex:null,ttype:y},{input:"dt",tag:"mi",output:"{:d t:}",tex:null,ttype:y},{input:"oint",tag:"mo",output:"\u222e",tex:null,ttype:0},{input:"del",tag:"mo",output:"\u2202",tex:"partial",ttype:0},{input:"grad",tag:"mo",output:"\u2207",tex:"nabla",ttype:0},{input:"+-",tag:"mo",output:"\xb1",tex:"pm",ttype:0},{input:"-+",tag:"mo",output:"\u2213",tex:"mp",ttype:0},{input:"O/",tag:"mo",output:"\u2205",tex:"emptyset",ttype:0},{input:"oo",tag:"mo",output:"\u221e",tex:"infty",ttype:0},{input:"aleph",tag:"mo",output:"\u2135",tex:null,ttype:0},{input:"...",tag:"mo",output:"...",tex:"ldots",ttype:0},{input:":.",tag:"mo",output:"\u2234",tex:"therefore",ttype:0},{input:":'",tag:"mo",output:"\u2235",tex:"because",ttype:0},{input:"/_",tag:"mo",output:"\u2220",tex:"angle",ttype:0},{input:"/_\\",tag:"mo",output:"\u25b3",tex:"triangle",ttype:0},{input:"'",tag:"mo",output:"\u2032",tex:"prime",ttype:0},{input:"tilde",tag:"mover",output:"~",tex:null,ttype:1,acc:!0},{input:"\\ ",tag:"mo",output:"\xa0",tex:null,ttype:0},{input:"frown",tag:"mo",output:"\u2322",tex:null,ttype:0},{input:"quad",tag:"mo",output:"\xa0\xa0",tex:null,ttype:0},{input:"qquad",tag:"mo",output:"\xa0\xa0\xa0\xa0",tex:null,ttype:0},{input:"cdots",tag:"mo",output:"\u22ef",tex:null,ttype:0},{input:"vdots",tag:"mo",output:"\u22ee",tex:null,ttype:0},{input:"ddots",tag:"mo",output:"\u22f1",tex:null,ttype:0},{input:"diamond",tag:"mo",output:"\u22c4",tex:null,ttype:0},{input:"square",tag:"mo",output:"\u25a1",tex:null,ttype:0},{input:"|__",tag:"mo",output:"\u230a",tex:"lfloor",ttype:0},{input:"__|",tag:"mo",output:"\u230b",tex:"rfloor",ttype:0},{input:"|~",tag:"mo",output:"\u2308",tex:"lceiling",ttype:0},{input:"~|",tag:"mo",output:"\u2309",tex:"rceiling",ttype:0},{input:"CC",tag:"mo",output:"\u2102",tex:null,ttype:0},{input:"NN",tag:"mo",output:"\u2115",tex:null,ttype:0},{input:"QQ",tag:"mo",output:"\u211a",tex:null,ttype:0},{input:"RR",tag:"mo",output:"\u211d",tex:null,ttype:0},{input:"ZZ",tag:"mo",output:"\u2124",tex:null,ttype:0},{input:"f",tag:"mi",output:"f",tex:null,ttype:1,func:!0},{input:"g",tag:"mi",output:"g",tex:null,ttype:1,func:!0},{input:"lim",tag:"mo",output:"lim",tex:null,ttype:7},{input:"Lim",tag:"mo",output:"Lim",tex:null,ttype:7},{input:"sin",tag:"mo",output:"sin",tex:null,ttype:1,func:!0},{input:"cos",tag:"mo",output:"cos",tex:null,ttype:1,func:!0},{input:"tan",tag:"mo",output:"tan",tex:null,ttype:1,func:!0},{input:"sinh",tag:"mo",output:"sinh",tex:null,ttype:1,func:!0},{input:"cosh",tag:"mo",output:"cosh",tex:null,ttype:1,func:!0},{input:"tanh",tag:"mo",output:"tanh",tex:null,ttype:1,func:!0},{input:"cot",tag:"mo",output:"cot",tex:null,ttype:1,func:!0},{input:"sec",tag:"mo",output:"sec",tex:null,ttype:1,func:!0},{input:"csc",tag:"mo",output:"csc",tex:null,ttype:1,func:!0},{input:"arcsin",tag:"mo",output:"arcsin",tex:null,ttype:1,func:!0},{input:"arccos",tag:"mo",output:"arccos",tex:null,ttype:1,func:!0},{input:"arctan",tag:"mo",output:"arctan",tex:null,ttype:1,func:!0},{input:"coth",tag:"mo",output:"coth",tex:null,ttype:1,func:!0},{input:"sech",tag:"mo",output:"sech",tex:null,ttype:1,func:!0},{input:"csch",tag:"mo",output:"csch",tex:null,ttype:1,func:!0},{input:"exp",tag:"mo",output:"exp",tex:null,ttype:1,func:!0},{input:"abs",tag:"mo",output:"abs",tex:null,ttype:1,rewriteleftright:["|","|"]},{input:"norm",tag:"mo",output:"norm",tex:null,ttype:1,rewriteleftright:["\u2225","\u2225"]},{input:"floor",tag:"mo",output:"floor",tex:null,ttype:1,rewriteleftright:["\u230a","\u230b"]},{input:"ceil",tag:"mo",output:"ceil",tex:null,ttype:1,rewriteleftright:["\u2308","\u2309"]},{input:"log",tag:"mo",output:"log",tex:null,ttype:1,func:!0},{input:"ln",tag:"mo",output:"ln",tex:null,ttype:1,func:!0},{input:"det",tag:"mo",output:"det",tex:null,ttype:1,func:!0},{input:"dim",tag:"mo",output:"dim",tex:null,ttype:0},{input:"mod",tag:"mo",output:"mod",tex:null,ttype:0},{input:"gcd",tag:"mo",output:"gcd",tex:null,ttype:1,func:!0},{input:"lcm",tag:"mo",output:"lcm",tex:null,ttype:1,func:!0},{input:"lub",tag:"mo",output:"lub",tex:null,ttype:0},{input:"glb",tag:"mo",output:"glb",tex:null,ttype:0},{input:"min",tag:"mo",output:"min",tex:null,ttype:7},{input:"max",tag:"mo",output:"max",tex:null,ttype:7},{input:"Sin",tag:"mo",output:"Sin",tex:null,ttype:1,func:!0},{input:"Cos",tag:"mo",output:"Cos",tex:null,ttype:1,func:!0},{input:"Tan",tag:"mo",output:"Tan",tex:null,ttype:1,func:!0},{input:"Arcsin",tag:"mo",output:"Arcsin",tex:null,ttype:1,func:!0},{input:"Arccos",tag:"mo",output:"Arccos",tex:null,ttype:1,func:!0},{input:"Arctan",tag:"mo",output:"Arctan",tex:null,ttype:1,func:!0},{input:"Sinh",tag:"mo",output:"Sinh",tex:null,ttype:1,func:!0},{input:"Cosh",tag:"mo",output:"Cosh",tex:null,ttype:1,func:!0},{input:"Tanh",tag:"mo",output:"Tanh",tex:null,ttype:1,func:!0},{input:"Cot",tag:"mo",output:"Cot",tex:null,ttype:1,func:!0},{input:"Sec",tag:"mo",output:"Sec",tex:null,ttype:1,func:!0},{input:"Csc",tag:"mo",output:"Csc",tex:null,ttype:1,func:!0},{input:"Log",tag:"mo",output:"Log",tex:null,ttype:1,func:!0},{input:"Ln",tag:"mo",output:"Ln",tex:null,ttype:1,func:!0},{input:"Abs",tag:"mo",output:"abs",tex:null,ttype:1,notexcopy:!0,rewriteleftright:["|","|"]},{input:"uarr",tag:"mo",output:"\u2191",tex:"uparrow",ttype:0},{input:"darr",tag:"mo",output:"\u2193",tex:"downarrow",ttype:0},{input:"rarr",tag:"mo",output:"\u2192",tex:"rightarrow",ttype:0},{input:"->",tag:"mo",output:"\u2192",tex:"to",ttype:0},{input:">->",tag:"mo",output:"\u21a3",tex:"rightarrowtail",ttype:0},{input:"->>",tag:"mo",output:"\u21a0",tex:"twoheadrightarrow",ttype:0},{input:">->>",tag:"mo",output:"\u2916",tex:"twoheadrightarrowtail",ttype:0},{input:"|->",tag:"mo",output:"\u21a6",tex:"mapsto",ttype:0},{input:"larr",tag:"mo",output:"\u2190",tex:"leftarrow",ttype:0},{input:"harr",tag:"mo",output:"\u2194",tex:"leftrightarrow",ttype:0},{input:"rArr",tag:"mo",output:"\u21d2",tex:"Rightarrow",ttype:0},{input:"lArr",tag:"mo",output:"\u21d0",tex:"Leftarrow",ttype:0},{input:"hArr",tag:"mo",output:"\u21d4",tex:"Leftrightarrow",ttype:0},{input:"sqrt",tag:"msqrt",output:"sqrt",tex:null,ttype:1},{input:"root",tag:"mroot",output:"root",tex:null,ttype:2},{input:"frac",tag:"mfrac",output:"/",tex:null,ttype:2},{input:"/",tag:"mfrac",output:"/",tex:null,ttype:3},{input:"stackrel",tag:"mover",output:"stackrel",tex:null,ttype:2},{input:"overset",tag:"mover",output:"stackrel",tex:null,ttype:2},{input:"underset",tag:"munder",output:"stackrel",tex:null,ttype:2},{input:"_",tag:"msub",output:"_",tex:null,ttype:3},{input:"^",tag:"msup",output:"^",tex:null,ttype:3},{input:"hat",tag:"mover",output:"^",tex:null,ttype:1,acc:!0},{input:"bar",tag:"mover",output:"\xaf",tex:"overline",ttype:1,acc:!0},{input:"vec",tag:"mover",output:"\u2192",tex:null,ttype:1,acc:!0},{input:"dot",tag:"mover",output:".",tex:null,ttype:1,acc:!0},{input:"ddot",tag:"mover",output:"..",tex:null,ttype:1,acc:!0},{input:"overarc",tag:"mover",output:"\u23dc",tex:"overparen",ttype:1,acc:!0},{input:"ul",tag:"munder",output:"\u0332",tex:"underline",ttype:1,acc:!0},{input:"ubrace",tag:"munder",output:"\u23df",tex:"underbrace",ttype:15,acc:!0},{input:"obrace",tag:"mover",output:"\u23de",tex:"overbrace",ttype:15,acc:!0},{input:"text",tag:"mtext",output:"text",tex:null,ttype:10},{input:"mbox",tag:"mtext",output:"mbox",tex:null,ttype:10},{input:"color",tag:"mstyle",ttype:2},{input:"id",tag:"mrow",ttype:2},{input:"class",tag:"mrow",ttype:2},{input:"cancel",tag:"menclose",output:"cancel",tex:null,ttype:1},E,{input:"bb",tag:"mstyle",atname:"mathvariant",atval:"bold",output:"bb",tex:null,ttype:1},{input:"mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",output:"mathbf",tex:null,ttype:1},{input:"sf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",output:"sf",tex:null,ttype:1},{input:"mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",output:"mathsf",tex:null,ttype:1},{input:"bbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",output:"bbb",tex:null,ttype:1,codes:g},{input:"mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",output:"mathbb",tex:null,ttype:1,codes:g},{input:"cc",tag:"mstyle",atname:"mathvariant",atval:"script",output:"cc",tex:null,ttype:1,codes:m},{input:"mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",output:"mathcal",tex:null,ttype:1,codes:m},{input:"tt",tag:"mstyle",atname:"mathvariant",atval:"monospace",output:"tt",tex:null,ttype:1},{input:"mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",output:"mathtt",tex:null,ttype:1},{input:"fr",tag:"mstyle",atname:"mathvariant",atval:"fraktur",output:"fr",tex:null,ttype:1,codes:f},{input:"mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",output:"mathfrak",tex:null,ttype:1,codes:f}];function T(t,e){return t.input>e.input?1:-1}var C,b,S,I=[];function N(){var t,e=x.length;for(t=0;t>1]=I[a];if(b=S,""!=s)return S=x[e].ttype,x[e];S=0,a=1,i=t.slice(0,1);for(var u=!0;"0"<=i&&i<="9"&&a<=t.length;)i=t.slice(a,a+1),a++;if(i==l&&"0"<=(i=t.slice(a,a+1))&&i<="9")for(u=!1,a++;"0"<=i&&i<="9"&&a<=t.length;)i=t.slice(a,a+1),a++;return u&&a>1||a>2?(i=t.slice(0,a-1),n="mn"):(a=2,n=("A">(i=t.slice(0,1))||i>"Z")&&("a">i||i>"z")?"mo":"mi"),"-"==i&&" "!==t.charAt(1)&&3==b?(S=3,{input:i,tag:n,output:i,ttype:1,func:!0}):{input:i,tag:n,output:i,ttype:0}}function L(t){var e;t.hasChildNodes()&&(!t.firstChild.hasChildNodes()||"mrow"!=t.nodeName&&"M:MROW"!=t.nodeName||"("!=(e=t.firstChild.firstChild.nodeValue)&&"["!=e&&"{"!=e||t.removeChild(t.firstChild),!t.lastChild.hasChildNodes()||"mrow"!=t.nodeName&&"M:MROW"!=t.nodeName||")"!=(e=t.lastChild.firstChild.nodeValue)&&"]"!=e&&"}"!=e||t.removeChild(t.lastChild))}function M(t){var e,i,a,s,r,o=n.createDocumentFragment();if(null==(e=O(t=v(t,0)))||5==e.ttype&&C>0)return[null,t];switch(e.ttype==y&&(e=O(t=e.output+v(t,e.input.length))),e.ttype){case 7:case 0:return t=v(t,e.input.length),[d(e.tag,n.createTextNode(e.output)),t];case 4:return C++,a=k(t=v(t,e.input.length),!0),C--,"boolean"==typeof e.invisible&&e.invisible?i=d("mrow",a[0]):(i=d("mo",n.createTextNode(e.output)),(i=d("mrow",i)).appendChild(a[0])),[i,a[1]];case 10:return e!=E&&(t=v(t,e.input.length)),-1==(s="{"==t.charAt(0)?t.indexOf("}"):"("==t.charAt(0)?t.indexOf(")"):"["==t.charAt(0)?t.indexOf("]"):e==E?t.slice(1).indexOf('"')+1:0)&&(s=t.length)," "==(r=t.slice(1,s)).charAt(0)&&((i=d("mspace")).setAttribute("width","1ex"),o.appendChild(i)),o.appendChild(d(e.tag,n.createTextNode(r)))," "==r.charAt(r.length-1)&&((i=d("mspace")).setAttribute("width","1ex"),o.appendChild(i)),t=v(t,s+1),[d("mrow",o),t];case 15:case 1:if(null==(a=M(t=v(t,e.input.length)))[0])return[d(e.tag,n.createTextNode(e.output)),t];if("boolean"==typeof e.func&&e.func)return"^"==(r=t.charAt(0))||"_"==r||"/"==r||"|"==r||","==r||1==e.input.length&&e.input.match(/\w/)&&"("!=r?[d(e.tag,n.createTextNode(e.output)),t]:((i=d("mrow",d(e.tag,n.createTextNode(e.output)))).appendChild(a[0]),[i,a[1]]);if(L(a[0]),"sqrt"==e.input)return[d(e.tag,a[0]),a[1]];if(void 0!==e.rewriteleftright)return(i=d("mrow",d("mo",n.createTextNode(e.rewriteleftright[0])))).appendChild(a[0]),i.appendChild(d("mo",n.createTextNode(e.rewriteleftright[1]))),[i,a[1]];if("cancel"==e.input)return(i=d(e.tag,a[0])).setAttribute("notation","updiagonalstrike"),[i,a[1]];if("boolean"==typeof e.acc&&e.acc){i=d(e.tag,a[0]);var l=d("mo",n.createTextNode(e.output));return"vec"==e.input&&("mrow"==a[0].nodeName&&1==a[0].childNodes.length&&null!==a[0].firstChild.firstChild.nodeValue&&1==a[0].firstChild.firstChild.nodeValue.length||null!==a[0].firstChild.nodeValue&&1==a[0].firstChild.nodeValue.length)&&l.setAttribute("stretchy",!1),i.appendChild(l),[i,a[1]]}if(!u&&void 0!==e.codes)for(s=0;s64&&r.charCodeAt(p)<91?h+=e.codes[r.charCodeAt(p)-65]:r.charCodeAt(p)>96&&r.charCodeAt(p)<123?h+=e.codes[r.charCodeAt(p)-71]:h+=r.charAt(p);"mi"==a[0].nodeName?a[0]=d("mo").appendChild(n.createTextNode(h)):a[0].replaceChild(d("mo").appendChild(n.createTextNode(h)),a[0].childNodes[s])}return(i=d(e.tag,a[0])).setAttribute(e.atname,e.atval),[i,a[1]];case 2:if(null==(a=M(t=v(t,e.input.length)))[0])return[d("mo",n.createTextNode(e.input)),t];L(a[0]);var c=M(a[1]);return null==c[0]?[d("mo",n.createTextNode(e.input)),t]:(L(c[0]),["color","class","id"].indexOf(e.input)>=0?("{"==t.charAt(0)?s=t.indexOf("}"):"("==t.charAt(0)?s=t.indexOf(")"):"["==t.charAt(0)&&(s=t.indexOf("]")),r=t.slice(1,s),i=d(e.tag,c[0]),"color"===e.input?i.setAttribute("mathcolor",r):"class"===e.input?i.setAttribute("class",r):"id"===e.input&&i.setAttribute("id",r),[i,c[1]]):("root"!=e.input&&"stackrel"!=e.output||o.appendChild(c[0]),o.appendChild(a[0]),"frac"==e.input&&o.appendChild(c[0]),[d(e.tag,o),c[1]]));case 3:return t=v(t,e.input.length),[d("mo",n.createTextNode(e.output)),t];case 6:return t=v(t,e.input.length),(i=d("mspace")).setAttribute("width","1ex"),o.appendChild(i),o.appendChild(d(e.tag,n.createTextNode(e.output))),(i=d("mspace")).setAttribute("width","1ex"),o.appendChild(i),[d("mrow",o),t];case 9:return C++,a=k(t=v(t,e.input.length),!1),C--,r="",null!=a[0].lastChild&&(r=a[0].lastChild.firstChild.nodeValue),"|"==r&&","!==t.charAt(0)?(i=d("mo",n.createTextNode(e.output)),(i=d("mrow",i)).appendChild(a[0]),[i,a[1]]):(i=d("mo",n.createTextNode("\u2223")),[i=d("mrow",i),t]);default:return t=v(t,e.input.length),[d(e.tag,n.createTextNode(e.output)),t]}}function D(t){var e,i,a,s,r,o;if(i=O(t=v(t,0)),s=(r=M(t))[0],3==(e=O(t=r[1])).ttype&&"/"!=e.input){if(null==(r=M(t=v(t,e.input.length)))[0]?r[0]=d("mo",n.createTextNode("\u25a1")):L(r[0]),t=r[1],o=7==i.ttype||15==i.ttype,"_"==e.input)if("^"==(a=O(t)).input){var l=M(t=v(t,a.input.length));L(l[0]),t=l[1],(s=d(o?"munderover":"msubsup",s)).appendChild(r[0]),s.appendChild(l[0]),s=d("mrow",s)}else(s=d(o?"munder":"msub",s)).appendChild(r[0]);else"^"==e.input&&o?(s=d("mover",s)).appendChild(r[0]):(s=d(e.tag,s)).appendChild(r[0]);void 0!==i.func&&i.func&&3!=(a=O(t)).ttype&&5!=a.ttype&&(i.input.length>1||4==a.ttype)&&(r=D(t),(s=d("mrow",s)).appendChild(r[0]),t=r[1])}return[s,t]}function k(t,e){var i,a,s,r,o=n.createDocumentFragment();do{a=(s=D(t=v(t,0)))[0],3==(i=O(t=s[1])).ttype&&"/"==i.input?(null==(s=D(t=v(t,i.input.length)))[0]?s[0]=d("mo",n.createTextNode("\u25a1")):L(s[0]),t=s[1],L(a),(a=d(i.tag,a)).appendChild(s[0]),o.appendChild(a),i=O(t)):null!=a&&o.appendChild(a)}while((5!=i.ttype&&(9!=i.ttype||e)||0==C)&&null!=i&&""!=i.output);if(5==i.ttype||9==i.ttype){var l=o.childNodes.length;if(l>0&&"mrow"==o.childNodes[l-1].nodeName&&o.childNodes[l-1].lastChild&&o.childNodes[l-1].lastChild.firstChild){var u=o.childNodes[l-1].lastChild.firstChild.nodeValue;if(")"==u||"]"==u){var h=o.childNodes[l-1].firstChild.firstChild.nodeValue;if("("==h&&")"==u&&"}"!=i.output||"["==h&&"]"==u){var p=[],c=!0,m=o.childNodes.length;for(r=0;c&&r1&&(c=p[r].length==p[r-2].length)}var g=[];if(c=c&&(p.length>1||p[0].length>0)){var y,E,x,T,b=n.createDocumentFragment();for(r=0;r2&&(o.removeChild(o.firstChild),o.removeChild(o.firstChild)),b.appendChild(d("mtr",y))}(a=d("mtable",b)).setAttribute("columnlines",g.join(" ")),"boolean"==typeof i.invisible&&i.invisible&&a.setAttribute("columnalign","left"),o.replaceChild(a,o.firstChild)}}}}t=v(t,i.input.length),"boolean"==typeof i.invisible&&i.invisible||(a=d("mo",n.createTextNode(i.output)),o.appendChild(a))}return[o,t]}function P(t,e){var i;return C=0,i=d("mstyle",k((t=(t=(t=t.replace(/ /g,"")).replace(/>/g,">")).replace(/</g,"<")).replace(/^\s+/g,""),!1)[0]),""!=s&&i.setAttribute("mathcolor",s),""!=mathfontsize&&(i.setAttribute("fontsize",mathfontsize),i.setAttribute("mathsize",mathfontsize)),""!=mathfontfamily&&(i.setAttribute("fontfamily",mathfontfamily),i.setAttribute("mathvariant",mathfontfamily)),r&&i.setAttribute("displaystyle","true"),i=d("math",i),o&&i.setAttribute("title",t.replace(/\s+/g," ")),i}o=!1,mathfontfamily="",s="",mathfontsize="",function(){for(var t=0,e=x.length;t=n-1&&(this.lastChild=t),this.SetData(i,t),t.nextSibling=e.nextSibling,e.nextSibling=e.parent=null,e},hasChildNodes:function(t){return this.childNodes.length>0},setAttribute:function(t,e){this[t]=e}}),N()},Augment:function(t){for(var e in t)if(t.hasOwnProperty(e)){switch(e){case"displaystyle":r=t[e];break;case"decimal":decimal=t[e];break;case"parseMath":P=t[e];break;case"parseExpr":k=t[e];break;case"parseIexpr":D=t[e];break;case"parseSexpr":M=t[e];break;case"removeBrackets":L=t[e];break;case"getSymbol":O=t[e];break;case"position":R=t[e];break;case"removeCharsAndBlanks":v=t[e];break;case"createMmlNode":d=t[e];break;case"createElementMathML":c=t[e];break;case"createElementXHTML":h=t[e];break;case"initSymbols":N=t[e];break;case"refreshSymbols":A=t[e];break;case"compareNames":T=t[e]}this[e]=t[e]}},parseMath:P,parseExpr:k,parseIexpr:D,parseSexr:M,removeBrackets:L,getSymbol:O,position:R,removeCharsAndBlanks:v,createMmlNode:d,createElementMathML:c,createElementXHTML:h,initSymbols:N,refreshSymbols:A,compareNames:T,createDocumentFragment:i,document:n,define:function(t,e){x.push({input:t,tag:"mo",output:e,tex:null,ttype:y}),A()},newcommand:function(t,e){x.push({input:t,tag:"mo",output:e,tex:null,ttype:y}),A()},newsymbol:function(t){x.push(t),A()},symbols:x,names:I,TOKEN:{CONST:0,UNARY:1,BINARY:2,INFIX:3,LEFTBRACKET:4,RIGHTBRACKET:5,SPACE:6,UNDEROVER:7,DEFINITION:y,LEFTRIGHT:9,TEXT:10,UNARYUNDEROVER:15}}})}(MathJax.InputJax.AsciiMath),(t=MathJax.InputJax.AsciiMath).Augment({sourceMenuTitle:["AsciiMathInput","AsciiMath Input"],annotationEncoding:"text/x-asciimath",prefilterHooks:MathJax.Callback.Hooks(!0),postfilterHooks:MathJax.Callback.Hooks(!0),Translate:function(t){var i,n=MathJax.HTML.getScript(t),a={math:n,script:t},s=this.prefilterHooks.Execute(a);if(s)return s;n=a.math;try{i=this.AM.parseMath(n)}catch(t){if(!t.asciimathError)throw t;i=this.formatError(t,n)}return a.math=e(i),this.postfilterHooks.Execute(a),this.postfilterHooks.Execute(a)||a.math},formatError:function(t,i,n){var a=t.message.replace(/\n.*/,"");return MathJax.Hub.signal.Post(["AsciiMath Jax - parse error",a,i,n]),e.Error(a)},Error:function(t){throw MathJax.Hub.Insert(Error(t),{asciimathError:!0})},Startup:function(){e=MathJax.ElementJax.mml,this.AM.Init()}}),t.loadComplete("jax.js")},723:function(t,e){"use strict";MathJax._.components.global.isObject,MathJax._.components.global.combineConfig,MathJax._.components.global.combineDefaults,e.r8=MathJax._.components.global.combineWithMathJax,MathJax._.components.global.MathJax},649:function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractFindMath=MathJax._.core.FindMath.AbstractFindMath},309:function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractInputJax=MathJax._.core.InputJax.AbstractInputJax},769:function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.protoItem=MathJax._.core.MathItem.protoItem,e.AbstractMathItem=MathJax._.core.MathItem.AbstractMathItem,e.STATE=MathJax._.core.MathItem.STATE,e.newState=MathJax._.core.MathItem.newState},806:function(t,e){"use strict";e.g=MathJax._.core.MmlTree.MmlFactory.MmlFactory},77:function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.APPEND=MathJax._.util.Options.APPEND,e.REMOVE=MathJax._.util.Options.REMOVE,e.Expandable=MathJax._.util.Options.Expandable,e.expandable=MathJax._.util.Options.expandable,e.makeArray=MathJax._.util.Options.makeArray,e.keys=MathJax._.util.Options.keys,e.copy=MathJax._.util.Options.copy,e.insert=MathJax._.util.Options.insert,e.defaultOptions=MathJax._.util.Options.defaultOptions,e.userOptions=MathJax._.util.Options.userOptions,e.selectOptions=MathJax._.util.Options.selectOptions,e.selectOptionsFromKeys=MathJax._.util.Options.selectOptionsFromKeys,e.separateOptions=MathJax._.util.Options.separateOptions},720:function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.sortLength=MathJax._.util.string.sortLength,e.quotePattern=MathJax._.util.string.quotePattern,e.unicodeChars=MathJax._.util.string.unicodeChars,e.unicodeString=MathJax._.util.string.unicodeString,e.isPercent=MathJax._.util.string.isPercent,e.split=MathJax._.util.string.split}},e={};function i(n){var a=e[n];if(void 0!==a)return a.exports;var s=e[n]={exports:{}};return t[n].call(s.exports,s,s.exports,i),s.exports}i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),function(){"use strict";var t=i(723),e=i(884),n=i(577);(0,t.r8)({_:{input:{asciimath_ts:e,asciimath:{FindAsciiMath:n}}}}),MathJax.startup&&(MathJax.startup.registerConstructor("asciimath",e.AsciiMath),MathJax.startup.useInput("asciimath"))}()}(); \ No newline at end of file diff --git a/docs/assets/vendor/mathjax/input/mml.js b/docs/assets/vendor/mathjax/input/mml.js new file mode 100644 index 0000000..077b42b --- /dev/null +++ b/docs/assets/vendor/mathjax/input/mml.js @@ -0,0 +1 @@ +!function(){"use strict";var t,e,r,a,o={236:function(t,e,r){var a,o=this&&this.__extends||(a=function(t,e){return(a=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])})(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}a(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var a,o,i=r.call(t),n=[];try{for(;(void 0===e||e-- >0)&&!(a=i.next()).done;)n.push(a.value)}catch(t){o={error:t}}finally{try{a&&!a.done&&(r=i.return)&&r.call(i)}finally{if(o)throw o.error}}return n};Object.defineProperty(e,"__esModule",{value:!0}),e.MathML=void 0;var n=r(309),s=r(77),l=r(898),h=r(794),p=r(332),c=function(t){function e(e){void 0===e&&(e={});var r=this,a=i(s.separateOptions(e,h.FindMathML.OPTIONS,p.MathMLCompile.OPTIONS),3),o=a[0],n=a[1],c=a[2];return(r=t.call(this,o)||this).findMathML=r.options.FindMathML||new h.FindMathML(n),r.mathml=r.options.MathMLCompile||new p.MathMLCompile(c),r.mmlFilters=new l.FunctionList,r}return o(e,t),e.prototype.setAdaptor=function(e){t.prototype.setAdaptor.call(this,e),this.findMathML.adaptor=e,this.mathml.adaptor=e},e.prototype.setMmlFactory=function(e){t.prototype.setMmlFactory.call(this,e),this.mathml.setMmlFactory(e)},Object.defineProperty(e.prototype,"processStrings",{get:function(){return!1},enumerable:!1,configurable:!0}),e.prototype.compile=function(t,e){var r=t.start.node;if(!r||!t.end.node||this.options.forceReparse||"#text"===this.adaptor.kind(r)){var a=this.executeFilters(this.preFilters,t,e,t.math||""),o=this.checkForErrors(this.adaptor.parse(a,"text/"+this.options.parseAs)),i=this.adaptor.body(o);1!==this.adaptor.childNodes(i).length&&this.error("MathML must consist of a single element"),r=this.adaptor.remove(this.adaptor.firstChild(i)),"math"!==this.adaptor.kind(r).replace(/^[a-z]+:/,"")&&this.error("MathML must be formed by a element, not <"+this.adaptor.kind(r)+">")}return r=this.executeFilters(this.mmlFilters,t,e,r),this.executeFilters(this.postFilters,t,e,this.mathml.compile(r))},e.prototype.checkForErrors=function(t){var e=this.adaptor.tags(this.adaptor.body(t),"parsererror")[0];return e&&(""===this.adaptor.textContent(e)&&this.error("Error processing MathML"),this.options.parseError.call(this,e)),t},e.prototype.error=function(t){throw new Error(t)},e.prototype.findMath=function(t){return this.findMathML.findMath(t)},e.NAME="MathML",e.OPTIONS=s.defaultOptions({parseAs:"html",forceReparse:!1,FindMathML:null,MathMLCompile:null,parseError:function(t){this.error(this.adaptor.textContent(t).replace(/\n.*/g,""))}},n.AbstractInputJax.OPTIONS),e}(n.AbstractInputJax);e.MathML=c},794:function(t,e,r){var a,o=this&&this.__extends||(a=function(t,e){return(a=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])})(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}a(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],a=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&a>=t.length&&(t=void 0),{value:t&&t[a++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.FindMathML=void 0;var n=r(649),s="http://www.w3.org/1998/Math/MathML",l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.findMath=function(t){var e=new Set;this.findMathNodes(t,e),this.findMathPrefixed(t,e);var r=this.adaptor.root(this.adaptor.document);return"html"===this.adaptor.kind(r)&&0===e.size&&this.findMathNS(t,e),this.processMath(e)},e.prototype.findMathNodes=function(t,e){var r,a;try{for(var o=i(this.adaptor.tags(t,"math")),n=o.next();!n.done;n=o.next()){var s=n.value;e.add(s)}}catch(t){r={error:t}}finally{try{n&&!n.done&&(a=o.return)&&a.call(o)}finally{if(r)throw r.error}}},e.prototype.findMathPrefixed=function(t,e){var r,a,o,n,l=this.adaptor.root(this.adaptor.document);try{for(var h=i(this.adaptor.allAttributes(l)),p=h.next();!p.done;p=h.next()){var c=p.value;if("xmlns:"===c.name.substr(0,6)&&c.value===s){var u=c.name.substr(6);try{for(var d=(o=void 0,i(this.adaptor.tags(t,u+":math"))),f=d.next();!f.done;f=d.next()){var M=f.value;e.add(M)}}catch(t){o={error:t}}finally{try{f&&!f.done&&(n=d.return)&&n.call(d)}finally{if(o)throw o.error}}}}}catch(t){r={error:t}}finally{try{p&&!p.done&&(a=h.return)&&a.call(h)}finally{if(r)throw r.error}}},e.prototype.findMathNS=function(t,e){var r,a;try{for(var o=i(this.adaptor.tags(t,"math",s)),n=o.next();!n.done;n=o.next()){var l=n.value;e.add(l)}}catch(t){r={error:t}}finally{try{n&&!n.done&&(a=o.return)&&a.call(o)}finally{if(r)throw r.error}}},e.prototype.processMath=function(t){var e,r,a=[];try{for(var o=i(Array.from(t)),n=o.next();!n.done;n=o.next()){var s=n.value,l="block"===this.adaptor.getAttribute(s,"display")||"display"===this.adaptor.getAttribute(s,"mode"),h={node:s,n:0,delim:""},p={node:s,n:0,delim:""};a.push({math:this.adaptor.outerHTML(s),start:h,end:p,display:l})}}catch(t){e={error:t}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}return a},e.OPTIONS={},e}(n.AbstractFindMath);e.FindMathML=l},332:function(t,e,r){var a=this&&this.__assign||function(){return(a=Object.assign||function(t){for(var e,r=1,a=arguments.length;r=t.length&&(t=void 0),{value:t&&t[a++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.MathMLCompile=void 0;var i=r(921),n=r(77),s=r(29),l=function(){function t(t){void 0===t&&(t={});var e=this.constructor;this.options=n.userOptions(n.defaultOptions({},e.OPTIONS),t)}return t.prototype.setMmlFactory=function(t){this.factory=t},t.prototype.compile=function(t){var e=this.makeNode(t);return e.verifyTree(this.options.verify),e.setInheritedAttributes({},!1,0,!1),e.walkTree(this.markMrows),e},t.prototype.makeNode=function(t){var e,r,a=this.adaptor,n=!1,s=a.kind(t).replace(/^.*:/,""),l=a.getAttribute(t,"data-mjx-texclass")||"";l&&(l=this.filterAttribute("data-mjx-texclass",l)||"");var h=l&&"mrow"===s?"TeXAtom":s;try{for(var p=o(this.filterClassList(a.allClasses(t))),c=p.next();!c.done;c=p.next()){var u=c.value;u.match(/^MJX-TeXAtom-/)?(l=u.substr(12),h="TeXAtom"):"MJX-fixedlimits"===u&&(n=!0)}}catch(t){e={error:t}}finally{try{c&&!c.done&&(r=p.return)&&r.call(p)}finally{if(e)throw e.error}}this.factory.getNodeClass(h)||this.error('Unknown node type "'+h+'"');var d=this.factory.create(h);return"TeXAtom"!==h||"OP"!==l||n||(d.setProperty("movesupsub",!0),d.attributes.setInherited("movablelimits",!0)),l&&(d.texClass=i.TEXCLASS[l],d.setProperty("texClass",d.texClass)),this.addAttributes(d,t),this.checkClass(d,t),this.addChildren(d,t),d},t.prototype.addAttributes=function(t,e){var r,a,i=!1;try{for(var n=o(this.adaptor.allAttributes(e)),s=n.next();!s.done;s=n.next()){var l=s.value,h=l.name,p=this.filterAttribute(h,l.value);if(null!==p&&"xmlns"!==h)if("data-mjx-"===h.substr(0,9))"data-mjx-alternate"===h?t.setProperty("variantForm",!0):"data-mjx-variant"===h?(t.attributes.set("mathvariant",p),i=!0):"data-mjx-smallmatrix"===h?(t.setProperty("scriptlevel",1),t.setProperty("useHeight",!1)):"data-mjx-accent"===h?t.setProperty("mathaccent","true"===p):"data-mjx-auto-op"===h&&t.setProperty("autoOP","true"===p);else if("class"!==h){var c=p.toLowerCase();"true"===c||"false"===c?t.attributes.set(h,"true"===c):i&&"mathvariant"===h||t.attributes.set(h,p)}}}catch(t){r={error:t}}finally{try{s&&!s.done&&(a=n.return)&&a.call(n)}finally{if(r)throw r.error}}},t.prototype.filterAttribute=function(t,e){return e},t.prototype.filterClassList=function(t){return t},t.prototype.addChildren=function(t,e){var r,a;if(0!==t.arity){var i=this.adaptor;try{for(var n=o(i.childNodes(e)),s=n.next();!s.done;s=n.next()){var l=s.value,h=i.kind(l);if("#comment"!==h)if("#text"===h)this.addText(t,l);else if(t.isKind("annotation-xml"))t.appendChild(this.factory.create("XML").setXML(l,i));else{var p=t.appendChild(this.makeNode(l));0===p.arity&&i.childNodes(l).length&&(this.options.fixMisplacedChildren?this.addChildren(t,l):p.mError("There should not be children for "+p.kind+" nodes",this.options.verify,!0))}}}catch(t){r={error:t}}finally{try{s&&!s.done&&(a=n.return)&&a.call(n)}finally{if(r)throw r.error}}}},t.prototype.addText=function(t,e){var r=this.adaptor.value(e);(t.isToken||t.getProperty("isChars"))&&t.arity?(t.isToken&&(r=s.translate(r),r=this.trimSpace(r)),t.appendChild(this.factory.create("text").setText(r))):r.match(/\S/)&&this.error('Unexpected text node "'+r+'"')},t.prototype.checkClass=function(t,e){var r,a,i=[];try{for(var n=o(this.filterClassList(this.adaptor.allClasses(e))),s=n.next();!s.done;s=n.next()){var l=s.value;"MJX-"===l.substr(0,4)?"MJX-variant"===l?t.setProperty("variantForm",!0):"MJX-TeXAtom"!==l.substr(0,11)&&t.attributes.set("mathvariant",this.fixCalligraphic(l.substr(3))):i.push(l)}}catch(t){r={error:t}}finally{try{s&&!s.done&&(a=n.return)&&a.call(n)}finally{if(r)throw r.error}}i.length&&t.attributes.set("class",i.join(" "))},t.prototype.fixCalligraphic=function(t){return t.replace(/caligraphic/,"calligraphic")},t.prototype.markMrows=function(t){if(t.isKind("mrow")&&!t.isInferred&&t.childNodes.length>=2){var e=t.childNodes[0],r=t.childNodes[t.childNodes.length-1];e.isKind("mo")&&e.attributes.get("fence")&&e.attributes.get("stretchy")&&r.isKind("mo")&&r.attributes.get("fence")&&r.attributes.get("stretchy")&&(e.childNodes.length&&t.setProperty("open",e.getText()),r.childNodes.length&&t.setProperty("close",r.getText()))}},t.prototype.trimSpace=function(t){return t.replace(/[\t\n\r]/g," ").replace(/^ +/,"").replace(/ +$/,"").replace(/ +/g," ")},t.prototype.error=function(t){throw new Error(t)},t.OPTIONS={MmlFactory:null,fixMisplacedChildren:!0,verify:a({},i.AbstractMmlNode.verifyDefaults),translateEntities:!0},t}();e.MathMLCompile=l},723:function(t,e){MathJax._.components.global.isObject,MathJax._.components.global.combineConfig,MathJax._.components.global.combineDefaults,e.r8=MathJax._.components.global.combineWithMathJax,MathJax._.components.global.MathJax},649:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractFindMath=MathJax._.core.FindMath.AbstractFindMath},309:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractInputJax=MathJax._.core.InputJax.AbstractInputJax},921:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.TEXCLASS=MathJax._.core.MmlTree.MmlNode.TEXCLASS,e.TEXCLASSNAMES=MathJax._.core.MmlTree.MmlNode.TEXCLASSNAMES,e.indentAttributes=MathJax._.core.MmlTree.MmlNode.indentAttributes,e.AbstractMmlNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlNode,e.AbstractMmlTokenNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlTokenNode,e.AbstractMmlLayoutNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlLayoutNode,e.AbstractMmlBaseNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlBaseNode,e.AbstractMmlEmptyNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlEmptyNode,e.TextNode=MathJax._.core.MmlTree.MmlNode.TextNode,e.XMLNode=MathJax._.core.MmlTree.MmlNode.XMLNode},29:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.options=MathJax._.util.Entities.options,e.entities=MathJax._.util.Entities.entities,e.add=MathJax._.util.Entities.add,e.remove=MathJax._.util.Entities.remove,e.translate=MathJax._.util.Entities.translate,e.numeric=MathJax._.util.Entities.numeric},898:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.FunctionList=MathJax._.util.FunctionList.FunctionList},77:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.APPEND=MathJax._.util.Options.APPEND,e.REMOVE=MathJax._.util.Options.REMOVE,e.Expandable=MathJax._.util.Options.Expandable,e.expandable=MathJax._.util.Options.expandable,e.makeArray=MathJax._.util.Options.makeArray,e.keys=MathJax._.util.Options.keys,e.copy=MathJax._.util.Options.copy,e.insert=MathJax._.util.Options.insert,e.defaultOptions=MathJax._.util.Options.defaultOptions,e.userOptions=MathJax._.util.Options.userOptions,e.selectOptions=MathJax._.util.Options.selectOptions,e.selectOptionsFromKeys=MathJax._.util.Options.selectOptionsFromKeys,e.separateOptions=MathJax._.util.Options.separateOptions}},i={};function n(t){var e=i[t];if(void 0!==e)return e.exports;var r=i[t]={exports:{}};return o[t].call(r.exports,r,r.exports,n),r.exports}t=n(723),e=n(236),r=n(794),a=n(332),(0,t.r8)({_:{input:{mathml_ts:e,mathml:{FindMathML:r,MathMLCompile:a}}}}),MathJax.startup&&(MathJax.startup.registerConstructor("mml",e.MathML),MathJax.startup.useInput("mml")),MathJax.loader&&MathJax.loader.pathFilters.add((function(t){return t.name=t.name.replace(/\/util\/entities\/.*?\.js/,"/input/mml/entities.js"),!0}))}(); \ No newline at end of file diff --git a/docs/assets/vendor/mathjax/input/mml/entities.js b/docs/assets/vendor/mathjax/input/mml/entities.js new file mode 100644 index 0000000..0bc7899 --- /dev/null +++ b/docs/assets/vendor/mathjax/input/mml/entities.js @@ -0,0 +1 @@ +!function(){"use strict";var r={170:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({AElig:"\xc6",AMP:"&",Aacute:"\xc1",Abreve:"\u0102",Acirc:"\xc2",Acy:"\u0410",Agrave:"\xc0",Alpha:"\u0391",Amacr:"\u0100",And:"\u2a53",Aogon:"\u0104",Aring:"\xc5",Assign:"\u2254",Atilde:"\xc3",Auml:"\xc4",aacute:"\xe1",abreve:"\u0103",ac:"\u223e",acE:"\u223e\u0333",acd:"\u223f",acirc:"\xe2",acy:"\u0430",aelig:"\xe6",af:"\u2061",agrave:"\xe0",alefsym:"\u2135",amacr:"\u0101",andand:"\u2a55",andd:"\u2a5c",andslope:"\u2a58",andv:"\u2a5a",ange:"\u29a4",angle:"\u2220",angmsdaa:"\u29a8",angmsdab:"\u29a9",angmsdac:"\u29aa",angmsdad:"\u29ab",angmsdae:"\u29ac",angmsdaf:"\u29ad",angmsdag:"\u29ae",angmsdah:"\u29af",angrt:"\u221f",angrtvb:"\u22be",angrtvbd:"\u299d",angst:"\xc5",angzarr:"\u237c",aogon:"\u0105",ap:"\u2248",apE:"\u2a70",apacir:"\u2a6f",apid:"\u224b",apos:"'",approx:"\u2248",approxeq:"\u224a",aring:"\xe5",ast:"*",asymp:"\u2248",asympeq:"\u224d",atilde:"\xe3",auml:"\xe4",awconint:"\u2233",awint:"\u2a11"},"a")},349:function(r,e,t){t(170),t(901),t(801),t(869),t(619),t(125),t(637),t(375),t(146),t(658),t(933),t(219),t(113),t(283),t(943),t(229),t(473),t(35),t(826),t(453),t(827),t(517),t(336),t(373),t(215),t(179),t(77),t(650),t(11)},901:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Barv:"\u2ae7",Barwed:"\u2306",Bcy:"\u0411",Bernoullis:"\u212c",Beta:"\u0392",Bumpeq:"\u224e",bNot:"\u2aed",backcong:"\u224c",backepsilon:"\u03f6",barvee:"\u22bd",barwed:"\u2305",barwedge:"\u2305",bbrk:"\u23b5",bbrktbrk:"\u23b6",bcong:"\u224c",bcy:"\u0431",bdquo:"\u201e",becaus:"\u2235",because:"\u2235",bemptyv:"\u29b0",bepsi:"\u03f6",bernou:"\u212c",bigcap:"\u22c2",bigcup:"\u22c3",bigvee:"\u22c1",bigwedge:"\u22c0",bkarow:"\u290d",blacksquare:"\u25aa",blacktriangleright:"\u25b8",blank:"\u2423",blk12:"\u2592",blk14:"\u2591",blk34:"\u2593",block:"\u2588",bne:"=\u20e5",bnequiv:"\u2261\u20e5",bnot:"\u2310",bot:"\u22a5",bottom:"\u22a5",boxDL:"\u2557",boxDR:"\u2554",boxDl:"\u2556",boxDr:"\u2553",boxH:"\u2550",boxHD:"\u2566",boxHU:"\u2569",boxHd:"\u2564",boxHu:"\u2567",boxUL:"\u255d",boxUR:"\u255a",boxUl:"\u255c",boxUr:"\u2559",boxV:"\u2551",boxVH:"\u256c",boxVL:"\u2563",boxVR:"\u2560",boxVh:"\u256b",boxVl:"\u2562",boxVr:"\u255f",boxbox:"\u29c9",boxdL:"\u2555",boxdR:"\u2552",boxh:"\u2500",boxhD:"\u2565",boxhU:"\u2568",boxhd:"\u252c",boxhu:"\u2534",boxuL:"\u255b",boxuR:"\u2558",boxv:"\u2502",boxvH:"\u256a",boxvL:"\u2561",boxvR:"\u255e",boxvh:"\u253c",boxvl:"\u2524",boxvr:"\u251c",bprime:"\u2035",breve:"\u02d8",brvbar:"\xa6",bsemi:"\u204f",bsim:"\u223d",bsime:"\u22cd",bsolb:"\u29c5",bsolhsub:"\u27c8",bullet:"\u2022",bump:"\u224e",bumpE:"\u2aae",bumpe:"\u224f",bumpeq:"\u224f"},"b")},801:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({CHcy:"\u0427",COPY:"\xa9",Cacute:"\u0106",CapitalDifferentialD:"\u2145",Cayleys:"\u212d",Ccaron:"\u010c",Ccedil:"\xc7",Ccirc:"\u0108",Cconint:"\u2230",Cdot:"\u010a",Cedilla:"\xb8",Chi:"\u03a7",ClockwiseContourIntegral:"\u2232",CloseCurlyDoubleQuote:"\u201d",CloseCurlyQuote:"\u2019",Colon:"\u2237",Colone:"\u2a74",Conint:"\u222f",CounterClockwiseContourIntegral:"\u2233",cacute:"\u0107",capand:"\u2a44",capbrcup:"\u2a49",capcap:"\u2a4b",capcup:"\u2a47",capdot:"\u2a40",caps:"\u2229\ufe00",caret:"\u2041",caron:"\u02c7",ccaps:"\u2a4d",ccaron:"\u010d",ccedil:"\xe7",ccirc:"\u0109",ccups:"\u2a4c",ccupssm:"\u2a50",cdot:"\u010b",cedil:"\xb8",cemptyv:"\u29b2",cent:"\xa2",centerdot:"\xb7",chcy:"\u0447",checkmark:"\u2713",cir:"\u25cb",cirE:"\u29c3",cire:"\u2257",cirfnint:"\u2a10",cirmid:"\u2aef",cirscir:"\u29c2",clubsuit:"\u2663",colone:"\u2254",coloneq:"\u2254",comma:",",commat:"@",compfn:"\u2218",complement:"\u2201",complexes:"\u2102",cong:"\u2245",congdot:"\u2a6d",conint:"\u222e",coprod:"\u2210",copy:"\xa9",copysr:"\u2117",crarr:"\u21b5",cross:"\u2717",csub:"\u2acf",csube:"\u2ad1",csup:"\u2ad0",csupe:"\u2ad2",cudarrl:"\u2938",cudarrr:"\u2935",cularrp:"\u293d",cupbrcap:"\u2a48",cupcap:"\u2a46",cupcup:"\u2a4a",cupdot:"\u228d",cupor:"\u2a45",cups:"\u222a\ufe00",curarrm:"\u293c",curlyeqprec:"\u22de",curlyeqsucc:"\u22df",curren:"\xa4",curvearrowleft:"\u21b6",curvearrowright:"\u21b7",cuvee:"\u22ce",cuwed:"\u22cf",cwconint:"\u2232",cwint:"\u2231",cylcty:"\u232d"},"c")},869:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({DD:"\u2145",DDotrahd:"\u2911",DJcy:"\u0402",DScy:"\u0405",DZcy:"\u040f",Darr:"\u21a1",Dashv:"\u2ae4",Dcaron:"\u010e",Dcy:"\u0414",DiacriticalAcute:"\xb4",DiacriticalDot:"\u02d9",DiacriticalDoubleAcute:"\u02dd",DiacriticalGrave:"`",DiacriticalTilde:"\u02dc",Dot:"\xa8",DotDot:"\u20dc",DoubleContourIntegral:"\u222f",DoubleDownArrow:"\u21d3",DoubleLeftArrow:"\u21d0",DoubleLeftRightArrow:"\u21d4",DoubleLeftTee:"\u2ae4",DoubleLongLeftArrow:"\u27f8",DoubleLongLeftRightArrow:"\u27fa",DoubleLongRightArrow:"\u27f9",DoubleRightArrow:"\u21d2",DoubleUpArrow:"\u21d1",DoubleUpDownArrow:"\u21d5",DownArrowBar:"\u2913",DownArrowUpArrow:"\u21f5",DownBreve:"\u0311",DownLeftRightVector:"\u2950",DownLeftTeeVector:"\u295e",DownLeftVectorBar:"\u2956",DownRightTeeVector:"\u295f",DownRightVectorBar:"\u2957",DownTeeArrow:"\u21a7",Dstrok:"\u0110",dArr:"\u21d3",dHar:"\u2965",darr:"\u2193",dash:"\u2010",dashv:"\u22a3",dbkarow:"\u290f",dblac:"\u02dd",dcaron:"\u010f",dcy:"\u0434",dd:"\u2146",ddagger:"\u2021",ddotseq:"\u2a77",demptyv:"\u29b1",dfisht:"\u297f",dharl:"\u21c3",dharr:"\u21c2",diam:"\u22c4",diamond:"\u22c4",diamondsuit:"\u2666",diams:"\u2666",die:"\xa8",disin:"\u22f2",divide:"\xf7",divonx:"\u22c7",djcy:"\u0452",dlcorn:"\u231e",dlcrop:"\u230d",dollar:"$",doteq:"\u2250",dotminus:"\u2238",doublebarwedge:"\u2306",downarrow:"\u2193",downdownarrows:"\u21ca",downharpoonleft:"\u21c3",downharpoonright:"\u21c2",drbkarow:"\u2910",drcorn:"\u231f",drcrop:"\u230c",dscy:"\u0455",dsol:"\u29f6",dstrok:"\u0111",dtri:"\u25bf",dtrif:"\u25be",duarr:"\u21f5",duhar:"\u296f",dwangle:"\u29a6",dzcy:"\u045f",dzigrarr:"\u27ff"},"d")},619:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({ENG:"\u014a",ETH:"\xd0",Eacute:"\xc9",Ecaron:"\u011a",Ecirc:"\xca",Ecy:"\u042d",Edot:"\u0116",Egrave:"\xc8",Emacr:"\u0112",EmptySmallSquare:"\u25fb",EmptyVerySmallSquare:"\u25ab",Eogon:"\u0118",Epsilon:"\u0395",Equal:"\u2a75",Esim:"\u2a73",Eta:"\u0397",Euml:"\xcb",eDDot:"\u2a77",eDot:"\u2251",eacute:"\xe9",easter:"\u2a6e",ecaron:"\u011b",ecirc:"\xea",ecolon:"\u2255",ecy:"\u044d",edot:"\u0117",ee:"\u2147",eg:"\u2a9a",egrave:"\xe8",egsdot:"\u2a98",el:"\u2a99",elinters:"\u23e7",elsdot:"\u2a97",emacr:"\u0113",emptyset:"\u2205",emptyv:"\u2205",emsp:"\u2003",emsp13:"\u2004",emsp14:"\u2005",eng:"\u014b",ensp:"\u2002",eogon:"\u0119",epar:"\u22d5",eparsl:"\u29e3",eplus:"\u2a71",epsilon:"\u03b5",eqcirc:"\u2256",eqcolon:"\u2255",eqsim:"\u2242",eqslantgtr:"\u2a96",eqslantless:"\u2a95",equals:"=",equest:"\u225f",equiv:"\u2261",equivDD:"\u2a78",eqvparsl:"\u29e5",erarr:"\u2971",esdot:"\u2250",esim:"\u2242",euml:"\xeb",euro:"\u20ac",excl:"!",exist:"\u2203",expectation:"\u2130",exponentiale:"\u2147"},"e")},125:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Fcy:"\u0424",FilledSmallSquare:"\u25fc",Fouriertrf:"\u2131",fallingdotseq:"\u2252",fcy:"\u0444",female:"\u2640",ffilig:"\ufb03",fflig:"\ufb00",ffllig:"\ufb04",filig:"\ufb01",fjlig:"fj",fllig:"\ufb02",fltns:"\u25b1",fnof:"\u0192",forall:"\u2200",forkv:"\u2ad9",fpartint:"\u2a0d",frac12:"\xbd",frac13:"\u2153",frac14:"\xbc",frac15:"\u2155",frac16:"\u2159",frac18:"\u215b",frac23:"\u2154",frac25:"\u2156",frac34:"\xbe",frac35:"\u2157",frac38:"\u215c",frac45:"\u2158",frac56:"\u215a",frac58:"\u215d",frac78:"\u215e",frasl:"\u2044"},"f")},77:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Afr:"\ud835\udd04",Bfr:"\ud835\udd05",Cfr:"\u212d",Dfr:"\ud835\udd07",Efr:"\ud835\udd08",Ffr:"\ud835\udd09",Gfr:"\ud835\udd0a",Hfr:"\u210c",Ifr:"\u2111",Jfr:"\ud835\udd0d",Kfr:"\ud835\udd0e",Lfr:"\ud835\udd0f",Mfr:"\ud835\udd10",Nfr:"\ud835\udd11",Ofr:"\ud835\udd12",Pfr:"\ud835\udd13",Qfr:"\ud835\udd14",Rfr:"\u211c",Sfr:"\ud835\udd16",Tfr:"\ud835\udd17",Ufr:"\ud835\udd18",Vfr:"\ud835\udd19",Wfr:"\ud835\udd1a",Xfr:"\ud835\udd1b",Yfr:"\ud835\udd1c",Zfr:"\u2128",afr:"\ud835\udd1e",bfr:"\ud835\udd1f",cfr:"\ud835\udd20",dfr:"\ud835\udd21",efr:"\ud835\udd22",ffr:"\ud835\udd23",gfr:"\ud835\udd24",hfr:"\ud835\udd25",ifr:"\ud835\udd26",jfr:"\ud835\udd27",kfr:"\ud835\udd28",lfr:"\ud835\udd29",mfr:"\ud835\udd2a",nfr:"\ud835\udd2b",ofr:"\ud835\udd2c",pfr:"\ud835\udd2d",qfr:"\ud835\udd2e",rfr:"\ud835\udd2f",sfr:"\ud835\udd30",tfr:"\ud835\udd31",ufr:"\ud835\udd32",vfr:"\ud835\udd33",wfr:"\ud835\udd34",xfr:"\ud835\udd35",yfr:"\ud835\udd36",zfr:"\ud835\udd37"},"fr")},637:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({GJcy:"\u0403",GT:">",Gammad:"\u03dc",Gbreve:"\u011e",Gcedil:"\u0122",Gcirc:"\u011c",Gcy:"\u0413",Gdot:"\u0120",GreaterGreater:"\u2aa2",Gt:"\u226b",gE:"\u2267",gacute:"\u01f5",gammad:"\u03dd",gbreve:"\u011f",gcirc:"\u011d",gcy:"\u0433",gdot:"\u0121",ge:"\u2265",gel:"\u22db",geq:"\u2265",geqq:"\u2267",geqslant:"\u2a7e",ges:"\u2a7e",gescc:"\u2aa9",gesdot:"\u2a80",gesdoto:"\u2a82",gesdotol:"\u2a84",gesl:"\u22db\ufe00",gesles:"\u2a94",gg:"\u226b",ggg:"\u22d9",gjcy:"\u0453",gl:"\u2277",glE:"\u2a92",gla:"\u2aa5",glj:"\u2aa4",gnapprox:"\u2a8a",gneq:"\u2a88",gneqq:"\u2269",grave:"`",gsim:"\u2273",gsime:"\u2a8e",gsiml:"\u2a90",gtcc:"\u2aa7",gtcir:"\u2a7a",gtlPar:"\u2995",gtquest:"\u2a7c",gtrapprox:"\u2a86",gtrarr:"\u2978",gtrdot:"\u22d7",gtreqless:"\u22db",gtreqqless:"\u2a8c",gtrless:"\u2277",gtrsim:"\u2273",gvertneqq:"\u2269\ufe00",gvnE:"\u2269\ufe00"},"g")},375:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({HARDcy:"\u042a",Hcirc:"\u0124",HilbertSpace:"\u210b",HorizontalLine:"\u2500",Hstrok:"\u0126",hArr:"\u21d4",hairsp:"\u200a",half:"\xbd",hamilt:"\u210b",hardcy:"\u044a",harr:"\u2194",harrcir:"\u2948",hcirc:"\u0125",hearts:"\u2665",heartsuit:"\u2665",hercon:"\u22b9",hksearow:"\u2925",hkswarow:"\u2926",hoarr:"\u21ff",homtht:"\u223b",horbar:"\u2015",hslash:"\u210f",hstrok:"\u0127",hybull:"\u2043",hyphen:"\u2010"},"h")},146:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({IEcy:"\u0415",IJlig:"\u0132",IOcy:"\u0401",Iacute:"\xcd",Icirc:"\xce",Icy:"\u0418",Idot:"\u0130",Igrave:"\xcc",Imacr:"\u012a",Implies:"\u21d2",Int:"\u222c",Iogon:"\u012e",Iota:"\u0399",Itilde:"\u0128",Iukcy:"\u0406",Iuml:"\xcf",iacute:"\xed",ic:"\u2063",icirc:"\xee",icy:"\u0438",iecy:"\u0435",iexcl:"\xa1",iff:"\u21d4",igrave:"\xec",ii:"\u2148",iiiint:"\u2a0c",iiint:"\u222d",iinfin:"\u29dc",iiota:"\u2129",ijlig:"\u0133",imacr:"\u012b",image:"\u2111",imagline:"\u2110",imagpart:"\u2111",imof:"\u22b7",imped:"\u01b5",in:"\u2208",incare:"\u2105",infintie:"\u29dd",inodot:"\u0131",int:"\u222b",integers:"\u2124",intercal:"\u22ba",intlarhk:"\u2a17",intprod:"\u2a3c",iocy:"\u0451",iogon:"\u012f",iprod:"\u2a3c",iquest:"\xbf",isin:"\u2208",isinE:"\u22f9",isindot:"\u22f5",isins:"\u22f4",isinsv:"\u22f3",isinv:"\u2208",it:"\u2062",itilde:"\u0129",iukcy:"\u0456",iuml:"\xef"},"i")},658:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Jcirc:"\u0134",Jcy:"\u0419",Jsercy:"\u0408",Jukcy:"\u0404",jcirc:"\u0135",jcy:"\u0439",jsercy:"\u0458",jukcy:"\u0454"},"j")},933:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({KHcy:"\u0425",KJcy:"\u040c",Kappa:"\u039a",Kcedil:"\u0136",Kcy:"\u041a",kcedil:"\u0137",kcy:"\u043a",kgreen:"\u0138",khcy:"\u0445",kjcy:"\u045c"},"k")},219:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({LJcy:"\u0409",LT:"<",Lacute:"\u0139",Lang:"\u27ea",Laplacetrf:"\u2112",Lcaron:"\u013d",Lcedil:"\u013b",Lcy:"\u041b",LeftArrowBar:"\u21e4",LeftDoubleBracket:"\u27e6",LeftDownTeeVector:"\u2961",LeftDownVectorBar:"\u2959",LeftRightVector:"\u294e",LeftTeeArrow:"\u21a4",LeftTeeVector:"\u295a",LeftTriangleBar:"\u29cf",LeftUpDownVector:"\u2951",LeftUpTeeVector:"\u2960",LeftUpVectorBar:"\u2958",LeftVectorBar:"\u2952",LessLess:"\u2aa1",Lmidot:"\u013f",LowerLeftArrow:"\u2199",LowerRightArrow:"\u2198",Lstrok:"\u0141",Lt:"\u226a",lAarr:"\u21da",lArr:"\u21d0",lAtail:"\u291b",lBarr:"\u290e",lE:"\u2266",lHar:"\u2962",lacute:"\u013a",laemptyv:"\u29b4",lagran:"\u2112",lang:"\u27e8",langd:"\u2991",langle:"\u27e8",laquo:"\xab",larr:"\u2190",larrb:"\u21e4",larrbfs:"\u291f",larrfs:"\u291d",larrhk:"\u21a9",larrpl:"\u2939",larrsim:"\u2973",lat:"\u2aab",latail:"\u2919",late:"\u2aad",lates:"\u2aad\ufe00",lbarr:"\u290c",lbbrk:"\u2772",lbrke:"\u298b",lbrksld:"\u298f",lbrkslu:"\u298d",lcaron:"\u013e",lcedil:"\u013c",lceil:"\u2308",lcub:"{",lcy:"\u043b",ldca:"\u2936",ldquo:"\u201c",ldquor:"\u201e",ldrdhar:"\u2967",ldrushar:"\u294b",ldsh:"\u21b2",leftarrow:"\u2190",leftarrowtail:"\u21a2",leftharpoondown:"\u21bd",leftharpoonup:"\u21bc",leftrightarrow:"\u2194",leftrightarrows:"\u21c6",leftrightharpoons:"\u21cb",leftrightsquigarrow:"\u21ad",leg:"\u22da",leq:"\u2264",leqq:"\u2266",leqslant:"\u2a7d",les:"\u2a7d",lescc:"\u2aa8",lesdot:"\u2a7f",lesdoto:"\u2a81",lesdotor:"\u2a83",lesg:"\u22da\ufe00",lesges:"\u2a93",lessapprox:"\u2a85",lesseqgtr:"\u22da",lesseqqgtr:"\u2a8b",lessgtr:"\u2276",lesssim:"\u2272",lfisht:"\u297c",lfloor:"\u230a",lg:"\u2276",lgE:"\u2a91",lhard:"\u21bd",lharu:"\u21bc",lharul:"\u296a",lhblk:"\u2584",ljcy:"\u0459",ll:"\u226a",llarr:"\u21c7",llcorner:"\u231e",llhard:"\u296b",lltri:"\u25fa",lmidot:"\u0140",lmoustache:"\u23b0",lnapprox:"\u2a89",lneq:"\u2a87",lneqq:"\u2268",loang:"\u27ec",loarr:"\u21fd",lobrk:"\u27e6",longleftarrow:"\u27f5",longleftrightarrow:"\u27f7",longrightarrow:"\u27f6",looparrowleft:"\u21ab",lopar:"\u2985",loplus:"\u2a2d",lotimes:"\u2a34",lowbar:"_",lozenge:"\u25ca",lozf:"\u29eb",lpar:"(",lparlt:"\u2993",lrarr:"\u21c6",lrcorner:"\u231f",lrhar:"\u21cb",lrhard:"\u296d",lrm:"\u200e",lrtri:"\u22bf",lsaquo:"\u2039",lsh:"\u21b0",lsim:"\u2272",lsime:"\u2a8d",lsimg:"\u2a8f",lsqb:"[",lsquo:"\u2018",lsquor:"\u201a",lstrok:"\u0142",ltcc:"\u2aa6",ltcir:"\u2a79",ltdot:"\u22d6",lthree:"\u22cb",ltlarr:"\u2976",ltquest:"\u2a7b",ltrPar:"\u2996",ltrie:"\u22b4",ltrif:"\u25c2",lurdshar:"\u294a",luruhar:"\u2966",lvertneqq:"\u2268\ufe00",lvnE:"\u2268\ufe00"},"l")},113:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Map:"\u2905",Mcy:"\u041c",MediumSpace:"\u205f",Mellintrf:"\u2133",Mu:"\u039c",mDDot:"\u223a",male:"\u2642",maltese:"\u2720",map:"\u21a6",mapsto:"\u21a6",mapstodown:"\u21a7",mapstoleft:"\u21a4",mapstoup:"\u21a5",marker:"\u25ae",mcomma:"\u2a29",mcy:"\u043c",mdash:"\u2014",measuredangle:"\u2221",micro:"\xb5",mid:"\u2223",midast:"*",midcir:"\u2af0",middot:"\xb7",minus:"\u2212",minusb:"\u229f",minusd:"\u2238",minusdu:"\u2a2a",mlcp:"\u2adb",mldr:"\u2026",mnplus:"\u2213",models:"\u22a7",mp:"\u2213",mstpos:"\u223e",mumap:"\u22b8"},"m")},283:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({NJcy:"\u040a",Nacute:"\u0143",Ncaron:"\u0147",Ncedil:"\u0145",Ncy:"\u041d",NegativeMediumSpace:"\u200b",NegativeThickSpace:"\u200b",NegativeThinSpace:"\u200b",NegativeVeryThinSpace:"\u200b",NewLine:"\n",NoBreak:"\u2060",NonBreakingSpace:"\xa0",Not:"\u2aec",NotCongruent:"\u2262",NotCupCap:"\u226d",NotEqualTilde:"\u2242\u0338",NotGreaterFullEqual:"\u2267\u0338",NotGreaterGreater:"\u226b\u0338",NotGreaterLess:"\u2279",NotGreaterSlantEqual:"\u2a7e\u0338",NotGreaterTilde:"\u2275",NotHumpDownHump:"\u224e\u0338",NotHumpEqual:"\u224f\u0338",NotLeftTriangleBar:"\u29cf\u0338",NotLessGreater:"\u2278",NotLessLess:"\u226a\u0338",NotLessSlantEqual:"\u2a7d\u0338",NotLessTilde:"\u2274",NotNestedGreaterGreater:"\u2aa2\u0338",NotNestedLessLess:"\u2aa1\u0338",NotPrecedesEqual:"\u2aaf\u0338",NotReverseElement:"\u220c",NotRightTriangleBar:"\u29d0\u0338",NotSquareSubset:"\u228f\u0338",NotSquareSubsetEqual:"\u22e2",NotSquareSuperset:"\u2290\u0338",NotSquareSupersetEqual:"\u22e3",NotSubset:"\u2282\u20d2",NotSucceedsEqual:"\u2ab0\u0338",NotSucceedsTilde:"\u227f\u0338",NotSuperset:"\u2283\u20d2",NotTildeEqual:"\u2244",NotTildeFullEqual:"\u2247",NotTildeTilde:"\u2249",Ntilde:"\xd1",Nu:"\u039d",nGg:"\u22d9\u0338",nGt:"\u226b\u20d2",nGtv:"\u226b\u0338",nLl:"\u22d8\u0338",nLt:"\u226a\u20d2",nLtv:"\u226a\u0338",nabla:"\u2207",nacute:"\u0144",nang:"\u2220\u20d2",nap:"\u2249",napE:"\u2a70\u0338",napid:"\u224b\u0338",napos:"\u0149",napprox:"\u2249",natural:"\u266e",naturals:"\u2115",nbsp:"\xa0",nbump:"\u224e\u0338",nbumpe:"\u224f\u0338",ncap:"\u2a43",ncaron:"\u0148",ncedil:"\u0146",ncong:"\u2247",ncongdot:"\u2a6d\u0338",ncup:"\u2a42",ncy:"\u043d",ndash:"\u2013",ne:"\u2260",neArr:"\u21d7",nearhk:"\u2924",nearrow:"\u2197",nedot:"\u2250\u0338",nequiv:"\u2262",nesear:"\u2928",nesim:"\u2242\u0338",nexist:"\u2204",nexists:"\u2204",ngE:"\u2267\u0338",nge:"\u2271",ngeq:"\u2271",ngeqq:"\u2267\u0338",ngeqslant:"\u2a7e\u0338",nges:"\u2a7e\u0338",ngsim:"\u2275",ngt:"\u226f",ngtr:"\u226f",nhArr:"\u21ce",nhpar:"\u2af2",ni:"\u220b",nis:"\u22fc",nisd:"\u22fa",niv:"\u220b",njcy:"\u045a",nlArr:"\u21cd",nlE:"\u2266\u0338",nldr:"\u2025",nle:"\u2270",nleftarrow:"\u219a",nleftrightarrow:"\u21ae",nleq:"\u2270",nleqq:"\u2266\u0338",nleqslant:"\u2a7d\u0338",nles:"\u2a7d\u0338",nless:"\u226e",nlsim:"\u2274",nlt:"\u226e",nltri:"\u22ea",nltrie:"\u22ec",nmid:"\u2224",notin:"\u2209",notinE:"\u22f9\u0338",notindot:"\u22f5\u0338",notinva:"\u2209",notinvb:"\u22f7",notinvc:"\u22f6",notni:"\u220c",notniva:"\u220c",notnivb:"\u22fe",notnivc:"\u22fd",npar:"\u2226",nparallel:"\u2226",nparsl:"\u2afd\u20e5",npart:"\u2202\u0338",npolint:"\u2a14",npr:"\u2280",nprcue:"\u22e0",npre:"\u2aaf\u0338",nprec:"\u2280",npreceq:"\u2aaf\u0338",nrArr:"\u21cf",nrarrc:"\u2933\u0338",nrarrw:"\u219d\u0338",nrightarrow:"\u219b",nrtri:"\u22eb",nrtrie:"\u22ed",nsc:"\u2281",nsccue:"\u22e1",nsce:"\u2ab0\u0338",nshortmid:"\u2224",nshortparallel:"\u2226",nsim:"\u2241",nsime:"\u2244",nsimeq:"\u2244",nsmid:"\u2224",nspar:"\u2226",nsqsube:"\u22e2",nsqsupe:"\u22e3",nsub:"\u2284",nsubE:"\u2ac5\u0338",nsube:"\u2288",nsubset:"\u2282\u20d2",nsubseteq:"\u2288",nsubseteqq:"\u2ac5\u0338",nsucc:"\u2281",nsucceq:"\u2ab0\u0338",nsup:"\u2285",nsupE:"\u2ac6\u0338",nsupe:"\u2289",nsupset:"\u2283\u20d2",nsupseteq:"\u2289",nsupseteqq:"\u2ac6\u0338",ntgl:"\u2279",ntilde:"\xf1",ntlg:"\u2278",ntriangleleft:"\u22ea",ntrianglelefteq:"\u22ec",ntriangleright:"\u22eb",ntrianglerighteq:"\u22ed",num:"#",numero:"\u2116",numsp:"\u2007",nvHarr:"\u2904",nvap:"\u224d\u20d2",nvge:"\u2265\u20d2",nvgt:">\u20d2",nvinfin:"\u29de",nvlArr:"\u2902",nvle:"\u2264\u20d2",nvlt:"<\u20d2",nvltrie:"\u22b4\u20d2",nvrArr:"\u2903",nvrtrie:"\u22b5\u20d2",nvsim:"\u223c\u20d2",nwArr:"\u21d6",nwarhk:"\u2923",nwarrow:"\u2196",nwnear:"\u2927"},"n")},943:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({OElig:"\u0152",Oacute:"\xd3",Ocirc:"\xd4",Ocy:"\u041e",Odblac:"\u0150",Ograve:"\xd2",Omacr:"\u014c",Omicron:"\u039f",OpenCurlyDoubleQuote:"\u201c",OpenCurlyQuote:"\u2018",Or:"\u2a54",Oslash:"\xd8",Otilde:"\xd5",Otimes:"\u2a37",Ouml:"\xd6",OverBracket:"\u23b4",OverParenthesis:"\u23dc",oS:"\u24c8",oacute:"\xf3",oast:"\u229b",ocir:"\u229a",ocirc:"\xf4",ocy:"\u043e",odash:"\u229d",odblac:"\u0151",odiv:"\u2a38",odot:"\u2299",odsold:"\u29bc",oelig:"\u0153",ofcir:"\u29bf",ogon:"\u02db",ograve:"\xf2",ogt:"\u29c1",ohbar:"\u29b5",ohm:"\u03a9",oint:"\u222e",olarr:"\u21ba",olcir:"\u29be",olcross:"\u29bb",oline:"\u203e",olt:"\u29c0",omacr:"\u014d",omid:"\u29b6",ominus:"\u2296",opar:"\u29b7",operp:"\u29b9",oplus:"\u2295",orarr:"\u21bb",ord:"\u2a5d",order:"\u2134",orderof:"\u2134",ordf:"\xaa",ordm:"\xba",origof:"\u22b6",oror:"\u2a56",orslope:"\u2a57",orv:"\u2a5b",oslash:"\xf8",otilde:"\xf5",otimes:"\u2297",otimesas:"\u2a36",ouml:"\xf6",ovbar:"\u233d"},"o")},650:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Aopf:"\ud835\udd38",Bopf:"\ud835\udd39",Copf:"\u2102",Dopf:"\ud835\udd3b",Eopf:"\ud835\udd3c",Fopf:"\ud835\udd3d",Gopf:"\ud835\udd3e",Hopf:"\u210d",Iopf:"\ud835\udd40",Jopf:"\ud835\udd41",Kopf:"\ud835\udd42",Lopf:"\ud835\udd43",Mopf:"\ud835\udd44",Nopf:"\u2115",Oopf:"\ud835\udd46",Popf:"\u2119",Qopf:"\u211a",Ropf:"\u211d",Sopf:"\ud835\udd4a",Topf:"\ud835\udd4b",Uopf:"\ud835\udd4c",Vopf:"\ud835\udd4d",Wopf:"\ud835\udd4e",Xopf:"\ud835\udd4f",Yopf:"\ud835\udd50",Zopf:"\u2124",aopf:"\ud835\udd52",bopf:"\ud835\udd53",copf:"\ud835\udd54",dopf:"\ud835\udd55",eopf:"\ud835\udd56",fopf:"\ud835\udd57",gopf:"\ud835\udd58",hopf:"\ud835\udd59",iopf:"\ud835\udd5a",jopf:"\ud835\udd5b",kopf:"\ud835\udd5c",lopf:"\ud835\udd5d",mopf:"\ud835\udd5e",nopf:"\ud835\udd5f",oopf:"\ud835\udd60",popf:"\ud835\udd61",qopf:"\ud835\udd62",ropf:"\ud835\udd63",sopf:"\ud835\udd64",topf:"\ud835\udd65",uopf:"\ud835\udd66",vopf:"\ud835\udd67",wopf:"\ud835\udd68",xopf:"\ud835\udd69",yopf:"\ud835\udd6a",zopf:"\ud835\udd6b"},"opf")},229:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Pcy:"\u041f",Poincareplane:"\u210c",Pr:"\u2abb",Prime:"\u2033",Proportion:"\u2237",par:"\u2225",para:"\xb6",parallel:"\u2225",parsim:"\u2af3",parsl:"\u2afd",part:"\u2202",pcy:"\u043f",percnt:"%",permil:"\u2030",perp:"\u22a5",pertenk:"\u2031",phmmat:"\u2133",phone:"\u260e",pitchfork:"\u22d4",planck:"\u210f",planckh:"\u210e",plankv:"\u210f",plus:"+",plusacir:"\u2a23",plusb:"\u229e",pluscir:"\u2a22",plusdo:"\u2214",plusdu:"\u2a25",pluse:"\u2a72",plusmn:"\xb1",plussim:"\u2a26",plustwo:"\u2a27",pm:"\xb1",pointint:"\u2a15",pound:"\xa3",pr:"\u227a",prE:"\u2ab3",prcue:"\u227c",pre:"\u2aaf",prec:"\u227a",precapprox:"\u2ab7",preccurlyeq:"\u227c",preceq:"\u2aaf",precsim:"\u227e",primes:"\u2119",prnE:"\u2ab5",prnap:"\u2ab9",prnsim:"\u22e8",prod:"\u220f",profalar:"\u232e",profline:"\u2312",profsurf:"\u2313",prop:"\u221d",propto:"\u221d",prsim:"\u227e",prurel:"\u22b0",puncsp:"\u2008"},"p")},473:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({QUOT:'"',qint:"\u2a0c",qprime:"\u2057",quaternions:"\u210d",quatint:"\u2a16",quest:"?",questeq:"\u225f"},"q")},35:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({RBarr:"\u2910",REG:"\xae",Racute:"\u0154",Rang:"\u27eb",Rarrtl:"\u2916",Rcaron:"\u0158",Rcedil:"\u0156",Rcy:"\u0420",ReverseElement:"\u220b",ReverseUpEquilibrium:"\u296f",Rho:"\u03a1",RightArrowBar:"\u21e5",RightDoubleBracket:"\u27e7",RightDownTeeVector:"\u295d",RightDownVectorBar:"\u2955",RightTeeVector:"\u295b",RightTriangleBar:"\u29d0",RightUpDownVector:"\u294f",RightUpTeeVector:"\u295c",RightUpVectorBar:"\u2954",RightVectorBar:"\u2953",RoundImplies:"\u2970",RuleDelayed:"\u29f4",rAarr:"\u21db",rArr:"\u21d2",rAtail:"\u291c",rBarr:"\u290f",rHar:"\u2964",race:"\u223d\u0331",racute:"\u0155",radic:"\u221a",raemptyv:"\u29b3",rang:"\u27e9",rangd:"\u2992",range:"\u29a5",rangle:"\u27e9",raquo:"\xbb",rarr:"\u2192",rarrap:"\u2975",rarrb:"\u21e5",rarrbfs:"\u2920",rarrc:"\u2933",rarrfs:"\u291e",rarrhk:"\u21aa",rarrlp:"\u21ac",rarrpl:"\u2945",rarrsim:"\u2974",rarrw:"\u219d",ratail:"\u291a",ratio:"\u2236",rationals:"\u211a",rbarr:"\u290d",rbbrk:"\u2773",rbrke:"\u298c",rbrksld:"\u298e",rbrkslu:"\u2990",rcaron:"\u0159",rcedil:"\u0157",rceil:"\u2309",rcub:"}",rcy:"\u0440",rdca:"\u2937",rdldhar:"\u2969",rdquo:"\u201d",rdquor:"\u201d",rdsh:"\u21b3",real:"\u211c",realine:"\u211b",realpart:"\u211c",reals:"\u211d",rect:"\u25ad",reg:"\xae",rfisht:"\u297d",rfloor:"\u230b",rhard:"\u21c1",rharu:"\u21c0",rharul:"\u296c",rightarrow:"\u2192",rightarrowtail:"\u21a3",rightharpoondown:"\u21c1",rightharpoonup:"\u21c0",rightleftarrows:"\u21c4",rightleftharpoons:"\u21cc",rightsquigarrow:"\u219d",risingdotseq:"\u2253",rlarr:"\u21c4",rlhar:"\u21cc",rlm:"\u200f",rmoustache:"\u23b1",rnmid:"\u2aee",roang:"\u27ed",roarr:"\u21fe",robrk:"\u27e7",ropar:"\u2986",roplus:"\u2a2e",rotimes:"\u2a35",rpar:")",rpargt:"\u2994",rppolint:"\u2a12",rrarr:"\u21c9",rsaquo:"\u203a",rsh:"\u21b1",rsqb:"]",rsquo:"\u2019",rsquor:"\u2019",rthree:"\u22cc",rtrie:"\u22b5",rtrif:"\u25b8",rtriltri:"\u29ce",ruluhar:"\u2968",rx:"\u211e"},"r")},826:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({SHCHcy:"\u0429",SHcy:"\u0428",SOFTcy:"\u042c",Sacute:"\u015a",Sc:"\u2abc",Scaron:"\u0160",Scedil:"\u015e",Scirc:"\u015c",Scy:"\u0421",ShortDownArrow:"\u2193",ShortLeftArrow:"\u2190",ShortRightArrow:"\u2192",ShortUpArrow:"\u2191",Sub:"\u22d0",Sup:"\u22d1",sacute:"\u015b",sbquo:"\u201a",sc:"\u227b",scE:"\u2ab4",scaron:"\u0161",sccue:"\u227d",sce:"\u2ab0",scedil:"\u015f",scirc:"\u015d",scpolint:"\u2a13",scsim:"\u227f",scy:"\u0441",sdotb:"\u22a1",sdote:"\u2a66",seArr:"\u21d8",searhk:"\u2925",searrow:"\u2198",semi:";",seswar:"\u2929",setminus:"\u2216",setmn:"\u2216",sext:"\u2736",sfrown:"\u2322",shchcy:"\u0449",shcy:"\u0448",shortmid:"\u2223",shortparallel:"\u2225",shy:"\xad",sigmaf:"\u03c2",sim:"\u223c",simdot:"\u2a6a",sime:"\u2243",simeq:"\u2243",simg:"\u2a9e",simgE:"\u2aa0",siml:"\u2a9d",simlE:"\u2a9f",simplus:"\u2a24",simrarr:"\u2972",slarr:"\u2190",smallsetminus:"\u2216",smashp:"\u2a33",smeparsl:"\u29e4",smid:"\u2223",smt:"\u2aaa",smte:"\u2aac",smtes:"\u2aac\ufe00",softcy:"\u044c",sol:"/",solb:"\u29c4",solbar:"\u233f",spadesuit:"\u2660",spar:"\u2225",sqcap:"\u2293",sqcaps:"\u2293\ufe00",sqcup:"\u2294",sqcups:"\u2294\ufe00",sqsub:"\u228f",sqsube:"\u2291",sqsubset:"\u228f",sqsubseteq:"\u2291",sqsup:"\u2290",sqsupe:"\u2292",sqsupset:"\u2290",sqsupseteq:"\u2292",squ:"\u25a1",square:"\u25a1",squarf:"\u25aa",squf:"\u25aa",srarr:"\u2192",ssetmn:"\u2216",ssmile:"\u2323",sstarf:"\u22c6",star:"\u2606",starf:"\u2605",straightepsilon:"\u03f5",straightphi:"\u03d5",strns:"\xaf",subdot:"\u2abd",sube:"\u2286",subedot:"\u2ac3",submult:"\u2ac1",subplus:"\u2abf",subrarr:"\u2979",subset:"\u2282",subseteq:"\u2286",subseteqq:"\u2ac5",subsetneq:"\u228a",subsetneqq:"\u2acb",subsim:"\u2ac7",subsub:"\u2ad5",subsup:"\u2ad3",succ:"\u227b",succapprox:"\u2ab8",succcurlyeq:"\u227d",succeq:"\u2ab0",succnapprox:"\u2aba",succneqq:"\u2ab6",succnsim:"\u22e9",succsim:"\u227f",sum:"\u2211",sung:"\u266a",sup:"\u2283",sup1:"\xb9",sup2:"\xb2",sup3:"\xb3",supdot:"\u2abe",supdsub:"\u2ad8",supe:"\u2287",supedot:"\u2ac4",suphsol:"\u27c9",suphsub:"\u2ad7",suplarr:"\u297b",supmult:"\u2ac2",supplus:"\u2ac0",supset:"\u2283",supseteq:"\u2287",supseteqq:"\u2ac6",supsetneq:"\u228b",supsetneqq:"\u2acc",supsim:"\u2ac8",supsub:"\u2ad4",supsup:"\u2ad6",swArr:"\u21d9",swarhk:"\u2926",swarrow:"\u2199",swnwar:"\u292a",szlig:"\xdf"},"s")},11:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Ascr:"\ud835\udc9c",Bscr:"\u212c",Cscr:"\ud835\udc9e",Dscr:"\ud835\udc9f",Escr:"\u2130",Fscr:"\u2131",Gscr:"\ud835\udca2",Hscr:"\u210b",Iscr:"\u2110",Jscr:"\ud835\udca5",Kscr:"\ud835\udca6",Lscr:"\u2112",Mscr:"\u2133",Nscr:"\ud835\udca9",Oscr:"\ud835\udcaa",Pscr:"\ud835\udcab",Qscr:"\ud835\udcac",Rscr:"\u211b",Sscr:"\ud835\udcae",Tscr:"\ud835\udcaf",Uscr:"\ud835\udcb0",Vscr:"\ud835\udcb1",Wscr:"\ud835\udcb2",Xscr:"\ud835\udcb3",Yscr:"\ud835\udcb4",Zscr:"\ud835\udcb5",ascr:"\ud835\udcb6",bscr:"\ud835\udcb7",cscr:"\ud835\udcb8",dscr:"\ud835\udcb9",escr:"\u212f",fscr:"\ud835\udcbb",gscr:"\u210a",hscr:"\ud835\udcbd",iscr:"\ud835\udcbe",jscr:"\ud835\udcbf",kscr:"\ud835\udcc0",lscr:"\ud835\udcc1",mscr:"\ud835\udcc2",nscr:"\ud835\udcc3",oscr:"\u2134",pscr:"\ud835\udcc5",qscr:"\ud835\udcc6",rscr:"\ud835\udcc7",sscr:"\ud835\udcc8",tscr:"\ud835\udcc9",uscr:"\ud835\udcca",vscr:"\ud835\udccb",wscr:"\ud835\udccc",xscr:"\ud835\udccd",yscr:"\ud835\udcce",zscr:"\ud835\udccf"},"scr")},453:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({THORN:"\xde",TRADE:"\u2122",TSHcy:"\u040b",TScy:"\u0426",Tab:"\t",Tau:"\u03a4",Tcaron:"\u0164",Tcedil:"\u0162",Tcy:"\u0422",ThickSpace:"\u205f\u200a",ThinSpace:"\u2009",TripleDot:"\u20db",Tstrok:"\u0166",target:"\u2316",tbrk:"\u23b4",tcaron:"\u0165",tcedil:"\u0163",tcy:"\u0442",tdot:"\u20db",telrec:"\u2315",there4:"\u2234",therefore:"\u2234",thetasym:"\u03d1",thickapprox:"\u2248",thicksim:"\u223c",thinsp:"\u2009",thkap:"\u2248",thksim:"\u223c",thorn:"\xfe",timesb:"\u22a0",timesbar:"\u2a31",timesd:"\u2a30",tint:"\u222d",toea:"\u2928",top:"\u22a4",topbot:"\u2336",topcir:"\u2af1",topfork:"\u2ada",tosa:"\u2929",tprime:"\u2034",trade:"\u2122",triangledown:"\u25bf",triangleleft:"\u25c3",trianglelefteq:"\u22b4",triangleright:"\u25b9",trianglerighteq:"\u22b5",tridot:"\u25ec",trie:"\u225c",triminus:"\u2a3a",triplus:"\u2a39",trisb:"\u29cd",tritime:"\u2a3b",trpezium:"\u23e2",tscy:"\u0446",tshcy:"\u045b",tstrok:"\u0167",twixt:"\u226c",twoheadleftarrow:"\u219e",twoheadrightarrow:"\u21a0"},"t")},827:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Uacute:"\xda",Uarr:"\u219f",Uarrocir:"\u2949",Ubrcy:"\u040e",Ubreve:"\u016c",Ucirc:"\xdb",Ucy:"\u0423",Udblac:"\u0170",Ugrave:"\xd9",Umacr:"\u016a",UnderBracket:"\u23b5",UnderParenthesis:"\u23dd",Uogon:"\u0172",UpArrowBar:"\u2912",UpArrowDownArrow:"\u21c5",UpEquilibrium:"\u296e",UpTeeArrow:"\u21a5",UpperLeftArrow:"\u2196",UpperRightArrow:"\u2197",Upsi:"\u03d2",Uring:"\u016e",Utilde:"\u0168",Uuml:"\xdc",uArr:"\u21d1",uHar:"\u2963",uacute:"\xfa",uarr:"\u2191",ubrcy:"\u045e",ubreve:"\u016d",ucirc:"\xfb",ucy:"\u0443",udarr:"\u21c5",udblac:"\u0171",udhar:"\u296e",ufisht:"\u297e",ugrave:"\xf9",uharl:"\u21bf",uharr:"\u21be",uhblk:"\u2580",ulcorn:"\u231c",ulcorner:"\u231c",ulcrop:"\u230f",ultri:"\u25f8",umacr:"\u016b",uml:"\xa8",uogon:"\u0173",uparrow:"\u2191",updownarrow:"\u2195",upharpoonleft:"\u21bf",upharpoonright:"\u21be",uplus:"\u228e",upsih:"\u03d2",upsilon:"\u03c5",urcorn:"\u231d",urcorner:"\u231d",urcrop:"\u230e",uring:"\u016f",urtri:"\u25f9",utdot:"\u22f0",utilde:"\u0169",utri:"\u25b5",utrif:"\u25b4",uuarr:"\u21c8",uuml:"\xfc",uwangle:"\u29a7"},"u")},517:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({VDash:"\u22ab",Vbar:"\u2aeb",Vcy:"\u0412",Vdashl:"\u2ae6",Verbar:"\u2016",Vert:"\u2016",VerticalLine:"|",VerticalSeparator:"\u2758",VeryThinSpace:"\u200a",vArr:"\u21d5",vBar:"\u2ae8",vBarv:"\u2ae9",vDash:"\u22a8",vangrt:"\u299c",varepsilon:"\u03f5",varkappa:"\u03f0",varnothing:"\u2205",varphi:"\u03d5",varpi:"\u03d6",varpropto:"\u221d",varr:"\u2195",varrho:"\u03f1",varsigma:"\u03c2",varsubsetneq:"\u228a\ufe00",varsubsetneqq:"\u2acb\ufe00",varsupsetneq:"\u228b\ufe00",varsupsetneqq:"\u2acc\ufe00",vartheta:"\u03d1",vartriangleleft:"\u22b2",vartriangleright:"\u22b3",vcy:"\u0432",vdash:"\u22a2",vee:"\u2228",veeeq:"\u225a",verbar:"|",vert:"|",vltri:"\u22b2",vnsub:"\u2282\u20d2",vnsup:"\u2283\u20d2",vprop:"\u221d",vrtri:"\u22b3",vsubnE:"\u2acb\ufe00",vsubne:"\u228a\ufe00",vsupnE:"\u2acc\ufe00",vsupne:"\u228b\ufe00",vzigzag:"\u299a"},"v")},336:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({Wcirc:"\u0174",wcirc:"\u0175",wedbar:"\u2a5f",wedge:"\u2227",wedgeq:"\u2259",wp:"\u2118",wr:"\u2240",wreath:"\u2240"},"w")},373:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({xcap:"\u22c2",xcirc:"\u25ef",xcup:"\u22c3",xdtri:"\u25bd",xhArr:"\u27fa",xharr:"\u27f7",xlArr:"\u27f8",xlarr:"\u27f5",xmap:"\u27fc",xnis:"\u22fb",xodot:"\u2a00",xoplus:"\u2a01",xotime:"\u2a02",xrArr:"\u27f9",xrarr:"\u27f6",xsqcup:"\u2a06",xuplus:"\u2a04",xutri:"\u25b3",xvee:"\u22c1",xwedge:"\u22c0"},"x")},215:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({YAcy:"\u042f",YIcy:"\u0407",YUcy:"\u042e",Yacute:"\xdd",Ycirc:"\u0176",Ycy:"\u042b",Yuml:"\u0178",yacute:"\xfd",yacy:"\u044f",ycirc:"\u0177",ycy:"\u044b",yicy:"\u0457",yucy:"\u044e",yuml:"\xff"},"y")},179:function(r,e,t){Object.defineProperty(e,"__esModule",{value:!0}),t(884).add({ZHcy:"\u0416",Zacute:"\u0179",Zcaron:"\u017d",Zcy:"\u0417",Zdot:"\u017b",ZeroWidthSpace:"\u200b",Zeta:"\u0396",zacute:"\u017a",zcaron:"\u017e",zcy:"\u0437",zdot:"\u017c",zeetrf:"\u2128",zhcy:"\u0436",zwj:"\u200d",zwnj:"\u200c"},"z")},884:function(r,e){Object.defineProperty(e,"__esModule",{value:!0}),e.options=MathJax._.util.Entities.options,e.entities=MathJax._.util.Entities.entities,e.add=MathJax._.util.Entities.add,e.remove=MathJax._.util.Entities.remove,e.translate=MathJax._.util.Entities.translate,e.numeric=MathJax._.util.Entities.numeric}},e={};function t(o){var a=e[o];if(void 0!==a)return a.exports;var s=e[o]={exports:{}};return r[o](s,s.exports,t),s.exports}t(349)}(); \ No newline at end of file diff --git a/docs/assets/vendor/mathjax/input/tex-full.js b/docs/assets/vendor/mathjax/input/tex-full.js new file mode 100644 index 0000000..de98c3a --- /dev/null +++ b/docs/assets/vendor/mathjax/input/tex-full.js @@ -0,0 +1,34 @@ +!function(){"use strict";var t={7205:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),a=this&&this.__assign||function(){return(a=Object.assign||function(t){for(var e,r=1,n=arguments.length;r0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(e,"__esModule",{value:!0}),e.TeX=void 0;var s=r(3309),l=r(9077),c=r(2982),u=r(199),p=r(8321),f=r(810),d=r(3466),h=r(6394),m=r(7251),g=r(6552);r(3606);var y=function(t){function e(r){void 0===r&&(r={});var n=this,o=i(l.separateOptions(r,e.OPTIONS,c.FindTeX.OPTIONS),3),a=o[0],s=o[1],p=o[2];(n=t.call(this,s)||this).findTeX=n.options.FindTeX||new c.FindTeX(p);var f=n.options.packages,d=n.configuration=e.configure(f),g=n._parseOptions=new h.default(d,[n.options,m.TagsFactory.OPTIONS]);return l.userOptions(g.options,a),d.config(n),e.tags(g,d),n.postFilters.add(u.default.cleanSubSup,-6),n.postFilters.add(u.default.setInherited,-5),n.postFilters.add(u.default.moveLimits,-4),n.postFilters.add(u.default.cleanStretchy,-3),n.postFilters.add(u.default.cleanAttributes,-2),n.postFilters.add(u.default.combineRelations,-1),n}return o(e,t),e.configure=function(t){var e=new g.ParserConfiguration(t);return e.init(),e},e.tags=function(t,e){m.TagsFactory.addTags(e.tags),m.TagsFactory.setDefault(t.options.tags),t.tags=m.TagsFactory.getDefault(),t.tags.configuration=t},e.prototype.setMmlFactory=function(e){t.prototype.setMmlFactory.call(this,e),this._parseOptions.nodeFactory.setMmlFactory(e)},Object.defineProperty(e.prototype,"parseOptions",{get:function(){return this._parseOptions},enumerable:!1,configurable:!0}),e.prototype.reset=function(t){void 0===t&&(t=0),this.parseOptions.tags.reset(t)},e.prototype.compile=function(t,e){this.parseOptions.clear(),this.executeFilters(this.preFilters,t,e,this.parseOptions);var r,n=t.display;this.latex=t.math,this.parseOptions.tags.startEquation(t);try{r=new f.default(this.latex,{display:n,isInner:!1},this.parseOptions).mml()}catch(t){if(!(t instanceof d.default))throw t;this.parseOptions.error=!0,r=this.options.formatError(this,t)}return r=this.parseOptions.nodeFactory.create("node","math",[r]),n&&p.default.setAttribute(r,"display","block"),this.parseOptions.tags.finishEquation(t),this.parseOptions.root=r,this.executeFilters(this.postFilters,t,e,this.parseOptions),this.mathNode=this.parseOptions.root,this.mathNode},e.prototype.findMath=function(t){return this.findTeX.findMath(t)},e.prototype.formatError=function(t){var e=t.message.replace(/\n.*/,"");return this.parseOptions.nodeFactory.create("error",e,t.id,this.latex)},e.NAME="TeX",e.OPTIONS=a(a({},s.AbstractInputJax.OPTIONS),{FindTeX:null,packages:["base"],digits:/^(?:[0-9]+(?:\{,\}[0-9]{3})*(?:\.[0-9]*)?|\.[0-9]+)/,maxBuffer:5120,formatError:function(t,e){return t.formatError(e)}}),e}(s.AbstractInputJax);e.TeX=y},2160:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.AllPackages=void 0,r(3606),r(1313),r(3946),r(6701),r(3067),r(9267),r(1677),r(7404),r(9489),r(4151),r(2298),r(3274),r(6755),r(5246),r(153),r(1323),r(2200),r(9569),r(8405),r(9589),r(7368),r(82),r(1158),r(4325),"undefined"!=typeof MathJax&&MathJax.loader&&MathJax.loader.preLoad("[tex]/action","[tex]/ams","[tex]/amscd","[tex]/bbox","[tex]/boldsymbol","[tex]/braket","[tex]/bussproofs","[tex]/cancel","[tex]/color","[tex]/colorv2","[tex]/enclose","[tex]/extpfeil","[tex]/html","[tex]/mhchem","[tex]/newcommand","[tex]/noerrors","[tex]/noundefined","[tex]/physics","[tex]/unicode","[tex]/verb","[tex]/configmacros","[tex]/tagformat","[tex]/textmacros"),e.AllPackages=["base","action","ams","amscd","bbox","boldsymbol","braket","bussproofs","cancel","color","enclose","extpfeil","html","mhchem","newcommand","noerrors","noundefined","unicode","verb","configmacros","tagformat","textmacros"]},6552:function(t,e,r){var n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(e,"__esModule",{value:!0}),e.ParserConfiguration=e.ConfigurationHandler=e.Configuration=void 0;var a,i=r(9077),s=r(2910),l=r(6898),c=r(4297),u=r(7251),p=function(){function t(t,e,r,n,o,a,i,s,l,c,u,p){void 0===e&&(e={}),void 0===r&&(r={}),void 0===n&&(n={}),void 0===o&&(o={}),void 0===a&&(a={}),void 0===i&&(i={}),void 0===s&&(s=[]),void 0===l&&(l=[]),void 0===c&&(c=null),void 0===u&&(u=null),this.name=t,this.handler=e,this.fallback=r,this.items=n,this.tags=o,this.options=a,this.nodes=i,this.preprocessors=s,this.postprocessors=l,this.initMethod=c,this.configMethod=u,this.priority=p,this.handler=Object.assign({character:[],delimiter:[],macro:[],environment:[]},e)}return t.makeProcessor=function(t,e){return Array.isArray(t)?t:[t,e]},t._create=function(e,r){var n=this;void 0===r&&(r={});var o=r.priority||c.PrioritizedList.DEFAULTPRIORITY,a=r.init?this.makeProcessor(r.init,o):null,i=r.config?this.makeProcessor(r.config,o):null,s=(r.preprocessors||[]).map((function(t){return n.makeProcessor(t,o)})),l=(r.postprocessors||[]).map((function(t){return n.makeProcessor(t,o)}));return new t(e,r.handler||{},r.fallback||{},r.items||{},r.tags||{},r.options||{},r.nodes||{},s,l,a,i,o)},t.create=function(e,r){void 0===r&&(r={});var n=t._create(e,r);return a.set(e,n),n},t.local=function(e){return void 0===e&&(e={}),t._create("",e)},Object.defineProperty(t.prototype,"init",{get:function(){return this.initMethod?this.initMethod[0]:null},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"config",{get:function(){return this.configMethod?this.configMethod[0]:null},enumerable:!1,configurable:!0}),t}();e.Configuration=p,function(t){var e=new Map;t.set=function(t,r){e.set(t,r)},t.get=function(t){return e.get(t)},t.keys=function(){return e.keys()}}(a=e.ConfigurationHandler||(e.ConfigurationHandler={}));var f=function(){function t(t){var e,r,o,a;this.initMethod=new l.FunctionList,this.configMethod=new l.FunctionList,this.configurations=new c.PrioritizedList,this.handlers=new s.SubHandlers,this.items={},this.tags={},this.options={},this.nodes={};try{for(var i=n(t.slice().reverse()),u=i.next();!u.done;u=i.next()){var p=u.value;this.addPackage(p)}}catch(t){e={error:t}}finally{try{u&&!u.done&&(r=i.return)&&r.call(i)}finally{if(e)throw e.error}}try{for(var f=n(this.configurations),d=f.next();!d.done;d=f.next()){var h=d.value,m=h.item,g=h.priority;this.append(m,g)}}catch(t){o={error:t}}finally{try{d&&!d.done&&(a=f.return)&&a.call(f)}finally{if(o)throw o.error}}}return t.prototype.init=function(){this.initMethod.execute(this)},t.prototype.config=function(t){var e,r;this.configMethod.execute(this,t);try{for(var o=n(this.configurations),a=o.next();!a.done;a=o.next()){var i=a.value;this.addFilters(t,i.item)}}catch(t){e={error:t}}finally{try{a&&!a.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}},t.prototype.addPackage=function(t){var e="string"==typeof t?t:t[0],r=a.get(e);r&&this.configurations.add(r,"string"==typeof t?r.priority:t[1])},t.prototype.add=function(t,e,r){var o,a;void 0===r&&(r={}),this.append(t),this.configurations.add(t,t.priority),this.init();var s=e.parseOptions;s.nodeFactory.setCreators(t.nodes);try{for(var l=n(Object.keys(t.items)),c=l.next();!c.done;c=l.next()){var p=c.value;s.itemFactory.setNodeClass(p,t.items[p])}}catch(t){o={error:t}}finally{try{c&&!c.done&&(a=l.return)&&a.call(l)}finally{if(o)throw o.error}}u.TagsFactory.addTags(t.tags),i.defaultOptions(s.options,t.options),i.userOptions(s.options,r),this.addFilters(e,t),t.config&&t.config(this,e)},t.prototype.append=function(t,e){e=e||t.priority,t.initMethod&&this.initMethod.add(t.initMethod[0],t.initMethod[1]),t.configMethod&&this.configMethod.add(t.configMethod[0],t.configMethod[1]),this.handlers.add(t.handler,t.fallback,e),Object.assign(this.items,t.items),Object.assign(this.tags,t.tags),i.defaultOptions(this.options,t.options),Object.assign(this.nodes,t.nodes)},t.prototype.addFilters=function(t,e){var r,a,i,s;try{for(var l=n(e.preprocessors),c=l.next();!c.done;c=l.next()){var u=o(c.value,2),p=u[0],f=u[1];t.preFilters.add(p,f)}}catch(t){r={error:t}}finally{try{c&&!c.done&&(a=l.return)&&a.call(l)}finally{if(r)throw r.error}}try{for(var d=n(e.postprocessors),h=d.next();!h.done;h=d.next()){var m=o(h.value,2),g=m[0];f=m[1];t.postFilters.add(g,f)}}catch(t){i={error:t}}finally{try{h&&!h.done&&(s=d.return)&&s.call(d)}finally{if(i)throw i.error}}},t}();e.ParserConfiguration=f},199:function(t,e,r){var n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0});var o,a=r(8921),i=r(8321);!function(t){t.cleanStretchy=function(t){var e,r,o=t.data;try{for(var a=n(o.getList("fixStretchy")),s=a.next();!s.done;s=a.next()){var l=s.value;if(i.default.getProperty(l,"fixStretchy")){var c=i.default.getForm(l);c&&c[3]&&c[3].stretchy&&i.default.setAttribute(l,"stretchy",!1);var u=l.parent;if(!(i.default.getTexClass(l)||c&&c[2])){var p=o.nodeFactory.create("node","TeXAtom",[l]);u.replaceChild(p,l),p.inheritAttributesFrom(l)}i.default.removeProperties(l,"fixStretchy")}}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=a.return)&&r.call(a)}finally{if(e)throw e.error}}},t.cleanAttributes=function(t){t.data.root.walkTree((function(t,e){var r,o,a=t.attributes;if(a)try{for(var i=n(a.getExplicitNames()),s=i.next();!s.done;s=i.next()){var l=s.value;a.attributes[l]===t.attributes.getInherited(l)&&delete a.attributes[l]}}catch(t){r={error:t}}finally{try{s&&!s.done&&(o=i.return)&&o.call(i)}finally{if(r)throw r.error}}}),{})},t.combineRelations=function(t){var o,s;try{for(var l=n(t.data.getList("mo")),c=l.next();!c.done;c=l.next()){var u=c.value;if(!u.getProperty("relationsCombined")&&u.parent&&(!u.parent||i.default.isType(u.parent,"mrow"))&&i.default.getTexClass(u)===a.TEXCLASS.REL){for(var p=u.parent,f=void 0,d=p.childNodes,h=d.indexOf(u)+1,m=i.default.getProperty(u,"variantForm");h0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(e,"__esModule",{value:!0}),e.FindTeX=void 0;var i=r(9649),s=r(6720),l=r(4769),c=function(t){function e(e){var r=t.call(this,e)||this;return r.getPatterns(),r}return o(e,t),e.prototype.getPatterns=function(){var t=this,e=this.options,r=[],n=[],o=[];this.end={},this.env=this.sub=0;var a=1;e.inlineMath.forEach((function(e){return t.addPattern(r,e,!1)})),e.displayMath.forEach((function(e){return t.addPattern(r,e,!0)})),r.length&&n.push(r.sort(s.sortLength).join("|")),e.processEnvironments&&(n.push("\\\\begin\\s*\\{([^}]*)\\}"),this.env=a,a++),e.processEscapes&&o.push("\\\\([\\\\$])"),e.processRefs&&o.push("(\\\\(?:eq)?ref\\s*\\{[^}]*\\})"),o.length&&(n.push("("+o.join("|")+")"),this.sub=a),this.start=new RegExp(n.join("|"),"g"),this.hasPatterns=n.length>0},e.prototype.addPattern=function(t,e,r){var n=a(e,2),o=n[0],i=n[1];t.push(s.quotePattern(o)),this.end[o]=[i,r,this.endPattern(i)]},e.prototype.endPattern=function(t,e){return new RegExp((e||s.quotePattern(t))+"|\\\\(?:[a-zA-Z]|.)|[{}]","g")},e.prototype.findEnd=function(t,e,r,n){for(var o,i=a(n,3),s=i[0],c=i[1],u=i[2],p=u.lastIndex=r.index+r[0].length,f=0;o=u.exec(t);){if((o[1]||o[0])===s&&0===f)return l.protoItem(r[0],t.substr(p,o.index-p),o[0],e,r.index,o.index+o[0].length,c);"{"===o[0]?f++:"}"===o[0]&&f&&f--}return null},e.prototype.findMathInString=function(t,e,r){var n,o;for(this.start.lastIndex=0;n=this.start.exec(r);){if(void 0!==n[this.env]&&this.env){var a="\\\\end\\s*(\\{"+s.quotePattern(n[this.env])+"\\})";(o=this.findEnd(r,e,n,["{"+n[this.env]+"}",!0,this.endPattern(null,a)]))&&(o.math=o.open+o.math+o.close,o.open=o.close="")}else if(void 0!==n[this.sub]&&this.sub){var i=n[this.sub];a=n.index+n[this.sub].length;o=2===i.length?l.protoItem("",i.substr(1),"",e,n.index,a):l.protoItem("",i,"",e,n.index,a,!1)}else o=this.findEnd(r,e,n,this.end[n[0]]);o&&(t.push(o),this.start.lastIndex=o.end.n)}},e.prototype.findMath=function(t){var e=[];if(this.hasPatterns)for(var r=0,n=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(e,"__esModule",{value:!0}),e.SubHandlers=e.SubHandler=e.MapHandler=void 0;var a,i=r(4297),s=r(6898);!function(t){var e=new Map;t.register=function(t){e.set(t.name,t)},t.getMap=function(t){return e.get(t)}}(a=e.MapHandler||(e.MapHandler={}));var l=function(){function t(){this._configuration=new i.PrioritizedList,this._fallback=new s.FunctionList}return t.prototype.add=function(t,e,r){var o,s;void 0===r&&(r=i.PrioritizedList.DEFAULTPRIORITY);try{for(var l=n(t.slice().reverse()),c=l.next();!c.done;c=l.next()){var u=c.value,p=a.getMap(u);if(!p)return void this.warn("Configuration "+u+" not found! Omitted.");this._configuration.add(p,r)}}catch(t){o={error:t}}finally{try{c&&!c.done&&(s=l.return)&&s.call(l)}finally{if(o)throw o.error}}e&&this._fallback.add(e,r)},t.prototype.parse=function(t){var e,r;try{for(var a=n(this._configuration),i=a.next();!i.done;i=a.next()){var s=i.value.item.parse(t);if(s)return s}}catch(t){e={error:t}}finally{try{i&&!i.done&&(r=a.return)&&r.call(a)}finally{if(e)throw e.error}}var l=o(t,2),c=l[0],u=l[1];this._fallback.toArray()[0].item(c,u)},t.prototype.lookup=function(t){var e=this.applicable(t);return e?e.lookup(t):null},t.prototype.contains=function(t){return!!this.applicable(t)},t.prototype.toString=function(){var t,e,r=[];try{for(var o=n(this._configuration),a=o.next();!a.done;a=o.next()){var i=a.value.item;r.push(i.name)}}catch(e){t={error:e}}finally{try{a&&!a.done&&(e=o.return)&&e.call(o)}finally{if(t)throw t.error}}return r.join(", ")},t.prototype.applicable=function(t){var e,r;try{for(var o=n(this._configuration),a=o.next();!a.done;a=o.next()){var i=a.value.item;if(i.contains(t))return i}}catch(t){e={error:t}}finally{try{a&&!a.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}return null},t.prototype.retrieve=function(t){var e,r;try{for(var o=n(this._configuration),a=o.next();!a.done;a=o.next()){var i=a.value.item;if(i.name===t)return i}}catch(t){e={error:t}}finally{try{a&&!a.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}return null},t.prototype.warn=function(t){console.log("TexParser Warning: "+t)},t}();e.SubHandler=l;var c=function(){function t(){this.map=new Map}return t.prototype.add=function(t,e,r){var o,a;void 0===r&&(r=i.PrioritizedList.DEFAULTPRIORITY);try{for(var s=n(Object.keys(t)),c=s.next();!c.done;c=s.next()){var u=c.value,p=this.get(u);p||(p=new l,this.set(u,p)),p.add(t[u],e[u],r)}}catch(t){o={error:t}}finally{try{c&&!c.done&&(a=s.return)&&a.call(s)}finally{if(o)throw o.error}}},t.prototype.set=function(t,e){this.map.set(t,e)},t.prototype.get=function(t){return this.map.get(t)},t.prototype.retrieve=function(t){var e,r;try{for(var o=n(this.map.values()),a=o.next();!a.done;a=o.next()){var i=a.value.retrieve(t);if(i)return i}}catch(t){e={error:t}}finally{try{a&&!a.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}return null},t.prototype.keys=function(){return this.map.keys()},t}();e.SubHandlers=c},8644:function(t,e,r){var n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},a=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0});var i=r(3239),s=r(8644),l=r(9077),c=function(){function t(t,e){void 0===e&&(e=[]),this.options={},this.packageData=new Map,this.parsers=[],this.root=null,this.nodeLists={},this.error=!1,this.handlers=t.handlers,this.nodeFactory=new s.NodeFactory,this.nodeFactory.configuration=this,this.nodeFactory.setCreators(t.nodes),this.itemFactory=new i.default(t.items),this.itemFactory.configuration=this,l.defaultOptions.apply(void 0,o([this.options],n(e))),l.defaultOptions(this.options,t.options)}return t.prototype.pushParser=function(t){this.parsers.unshift(t)},t.prototype.popParser=function(){this.parsers.shift()},Object.defineProperty(t.prototype,"parser",{get:function(){return this.parsers[0]},enumerable:!1,configurable:!0}),t.prototype.clear=function(){this.parsers=[],this.root=null,this.nodeLists={},this.error=!1,this.tags.resetTag()},t.prototype.addNode=function(t,e){var r=this.nodeLists[t];r||(r=this.nodeLists[t]=[]),r.push(e)},t.prototype.getList=function(t){var e,r,n=this.nodeLists[t]||[],o=[];try{for(var i=a(n),s=i.next();!s.done;s=i.next()){var l=s.value;this.inTree(l)&&o.push(l)}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=i.return)&&r.call(i)}finally{if(e)throw e.error}}return this.nodeLists[t]=o,o},t.prototype.inTree=function(t){for(;t&&t!==this.root;)t=t.parent;return!!t},t}();e.default=c},7702:function(t,e,r){var n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},o=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0});var a,i=r(8921),s=r(8321),l=r(810),c=r(3466),u=r(9029);!function(t){var e=7.2,r={em:function(t){return t},ex:function(t){return.43*t},pt:function(t){return t/10},pc:function(t){return 1.2*t},px:function(t){return t*e/72},in:function(t){return t*e},cm:function(t){return t*e/2.54},mm:function(t){return t*e/25.4},mu:function(t){return t/18}},a="([-+]?([.,]\\d+|\\d+([.,]\\d*)?))",p="(pt|em|ex|mu|px|mm|cm|in|pc)",f=RegExp("^\\s*"+a+"\\s*"+p+"\\s*$"),d=RegExp("^\\s*"+a+"\\s*"+p+" ?");function h(t,e){void 0===e&&(e=!1);var o=t.match(e?d:f);return o?function(t){var e=n(t,3),o=e[0],a=e[1],i=e[2];if("mu"!==a)return[o,a,i];return[m(r[a](parseFloat(o||"1"))).slice(0,-2),"em",i]}([o[1].replace(/,/,"."),o[4],o[0].length]):[null,null,0]}function m(t){return Math.abs(t)<6e-4?"0em":t.toFixed(3).replace(/\.?0+$/,"")+"em"}function g(t,e,r){"{"!==e&&"}"!==e||(e="\\"+e);var n="{\\bigg"+r+" "+e+"}",o="{\\big"+r+" "+e+"}";return new l.default("\\mathchoice"+n+o+o+o,{},t).mml()}function y(t,e,r){e=e.replace(/^\s+/,u.entities.nbsp).replace(/\s+$/,u.entities.nbsp);var n=t.create("text",e);return t.create("node","mtext",[],r,n)}function v(t,e,r){if(r.match(/^[a-z]/i)&&e.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)&&(e+=" "),e.length+r.length>t.configuration.options.maxBuffer)throw new c.default("MaxBufferSize","MathJax internal buffer size exceeded; is there a recursive macro call?");return e+r}function b(t,e){for(;e>0;)t=t.trim().slice(1,-1),e--;return t.trim()}function x(t,e){for(var r=t.length,n=0,o="",a=0,i=0,s=!0,l=!1;an&&(i=n)),n++;break;case"}":n&&n--,(s||l)&&(i--,l=!0),s=!1;break;default:if(!n&&-1!==e.indexOf(u))return[l?"true":b(o,i),u,t.slice(a)];s=!1,l=!1}o+=u}if(n)throw new c.default("ExtraOpenMissingClose","Extra open brace or missing close brace");return[l?"true":b(o,i),"",t.slice(a)]}t.matchDimen=h,t.dimen2em=function(t){var e=n(h(t),2),o=e[0],a=e[1],i=parseFloat(o||"1"),s=r[a];return s?s(i):0},t.Em=m,t.fenced=function(t,e,r,n,o,a){void 0===o&&(o=""),void 0===a&&(a="");var c,u=t.nodeFactory,p=u.create("node","mrow",[],{open:e,close:n,texClass:i.TEXCLASS.INNER});if(o)c=new l.default("\\"+o+"l"+e,t.parser.stack.env,t).mml();else{var f=u.create("text",e);c=u.create("node","mo",[],{fence:!0,stretchy:!0,symmetric:!0,texClass:i.TEXCLASS.OPEN},f)}if(s.default.appendChildren(p,[c,r]),o)c=new l.default("\\"+o+"r"+n,t.parser.stack.env,t).mml();else{var d=u.create("text",n);c=u.create("node","mo",[],{fence:!0,stretchy:!0,symmetric:!0,texClass:i.TEXCLASS.CLOSE},d)}return a&&c.attributes.set("mathcolor",a),s.default.appendChildren(p,[c]),p},t.fixedFence=function(t,e,r,n){var o=t.nodeFactory.create("node","mrow",[],{open:e,close:n,texClass:i.TEXCLASS.ORD});return e&&s.default.appendChildren(o,[g(t,e,"l")]),s.default.isType(r,"mrow")?s.default.appendChildren(o,s.default.getChildren(r)):s.default.appendChildren(o,[r]),n&&s.default.appendChildren(o,[g(t,n,"r")]),o},t.mathPalette=g,t.fixInitialMO=function(t,e){for(var r=0,n=e.length;r1&&(u=[t.create("node","mrow",u)]),u},t.internalText=y,t.trimSpaces=function(t){if("string"!=typeof t)return t;var e=t.trim();return e.match(/\\$/)&&t.match(/ $/)&&(e+=" "),e},t.setArrayAlign=function(e,r){return"t"===(r=t.trimSpaces(r||""))?e.arraydef.align="baseline 1":"b"===r?e.arraydef.align="baseline -1":"c"===r?e.arraydef.align="center":r&&(e.arraydef.align=r),e},t.substituteArgs=function(t,e,r){for(var n="",o="",a=0;ae.length)throw new c.default("IllegalMacroParam","Illegal macro parameter reference");o=v(t,v(t,o,n),e[parseInt(i,10)-1]),n=""}else n+=i}return v(t,o,n)},t.addArgs=v,t.checkEqnEnv=function(t){if(t.stack.global.eqnenv)throw new c.default("ErroneousNestingEq","Erroneous nesting of equation structures");t.stack.global.eqnenv=!0},t.MmlFilterAttribute=function(t,e,r){return r},t.getFontDef=function(t){var e=t.stack.env.font;return e?{mathvariant:e}:{}},t.keyvalOptions=function(t,e,r){var a,i;void 0===e&&(e=null),void 0===r&&(r=!1);var s=function(t){var e,r,o,a,i,s={},l=t;for(;l;)a=(e=n(x(l,["=",","]),3))[0],o=e[1],l=e[2],"="===o?(i=(r=n(x(l,[","]),3))[0],o=r[1],l=r[2],i="false"===i||"true"===i?JSON.parse(i):i,s[a]=i):a&&(s[a]=!0);return s}(t);if(e)try{for(var l=o(Object.keys(s)),u=l.next();!u.done;u=l.next()){var p=u.value;if(!e.hasOwnProperty(p)){if(r)throw new c.default("InvalidOption","Invalid optional argument: %1",p);delete s[p]}}}catch(t){a={error:t}}finally{try{u&&!u.done&&(i=l.return)&&i.call(l)}finally{if(a)throw a.error}}return s}}(a||(a={})),e.default=a},9874:function(t,e,r){var n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},a=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},i=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.BaseItem=e.MmlStack=void 0;var l=r(3466),c=function(){function t(t){this._nodes=t}return Object.defineProperty(t.prototype,"nodes",{get:function(){return this._nodes},enumerable:!1,configurable:!0}),t.prototype.Push=function(){for(var t,e=[],r=0;r0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.TagsFactory=e.AllTags=e.NoTags=e.AbstractTags=e.TagInfo=e.Label=void 0;var i=r(810),s=function(t,e){void 0===t&&(t="???"),void 0===e&&(e=""),this.tag=t,this.id=e};e.Label=s;var l=function(t,e,r,n,o,a,i,s){void 0===t&&(t=""),void 0===e&&(e=!1),void 0===r&&(r=!1),void 0===n&&(n=null),void 0===o&&(o=""),void 0===a&&(a=""),void 0===i&&(i=!1),void 0===s&&(s=""),this.env=t,this.taggable=e,this.defaultTags=r,this.tag=n,this.tagId=o,this.tagFormat=a,this.noTag=i,this.labelId=s};e.TagInfo=l;var c=function(){function t(){this.counter=0,this.allCounter=0,this.configuration=null,this.ids={},this.allIds={},this.labels={},this.allLabels={},this.redo=!1,this.refUpdate=!1,this.currentTag=new l,this.history=[],this.stack=[],this.enTag=function(t,e){var r=this.configuration.nodeFactory,n=r.create("node","mtd",[t]),o=r.create("node","mlabeledtr",[e,n]);return r.create("node","mtable",[o],{side:this.configuration.options.tagSide,minlabelspacing:this.configuration.options.tagIndent,displaystyle:!0})}}return t.prototype.start=function(t,e,r){this.currentTag&&this.stack.push(this.currentTag),this.currentTag=new l(t,e,r)},Object.defineProperty(t.prototype,"env",{get:function(){return this.currentTag.env},enumerable:!1,configurable:!0}),t.prototype.end=function(){this.history.push(this.currentTag),this.currentTag=this.stack.pop()},t.prototype.tag=function(t,e){this.currentTag.tag=t,this.currentTag.tagFormat=e?t:this.formatTag(t),this.currentTag.noTag=!1},t.prototype.notag=function(){this.tag("",!0),this.currentTag.noTag=!0},Object.defineProperty(t.prototype,"noTag",{get:function(){return this.currentTag.noTag},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"label",{get:function(){return this.currentTag.labelId},set:function(t){this.currentTag.labelId=t},enumerable:!1,configurable:!0}),t.prototype.formatUrl=function(t,e){return e+"#"+encodeURIComponent(t)},t.prototype.formatTag=function(t){return"("+t+")"},t.prototype.formatId=function(t){return"mjx-eqn:"+t.replace(/\s/g,"_")},t.prototype.formatNumber=function(t){return t.toString()},t.prototype.autoTag=function(){null==this.currentTag.tag&&(this.counter++,this.tag(this.formatNumber(this.counter),!1))},t.prototype.clearTag=function(){this.label="",this.tag(null,!0),this.currentTag.tagId=""},t.prototype.getTag=function(t){if(void 0===t&&(t=!1),t)return this.autoTag(),this.makeTag();var e=this.currentTag;return e.taggable&&!e.noTag&&(e.defaultTags&&this.autoTag(),e.tag)?this.makeTag():null},t.prototype.resetTag=function(){this.history=[],this.redo=!1,this.refUpdate=!1,this.clearTag()},t.prototype.reset=function(t){void 0===t&&(t=0),this.resetTag(),this.counter=this.allCounter=t,this.allLabels={},this.allIds={}},t.prototype.startEquation=function(t){this.history=[],this.stack=[],this.clearTag(),this.currentTag=new l("",void 0,void 0),this.labels={},this.ids={},this.counter=this.allCounter,this.redo=!1;var e=t.inputData.recompile;e&&(this.refUpdate=!0,this.counter=e.counter)},t.prototype.finishEquation=function(t){this.redo&&(t.inputData.recompile={state:t.state(),counter:this.allCounter}),this.refUpdate||(this.allCounter=this.counter),Object.assign(this.allIds,this.ids),Object.assign(this.allLabels,this.labels)},t.prototype.finalize=function(t,e){if(!e.display||this.currentTag.env||null==this.currentTag.tag)return t;var r=this.makeTag();return this.enTag(t,r)},t.prototype.makeId=function(){this.currentTag.tagId=this.formatId(this.configuration.options.useLabelIds&&this.label||this.currentTag.tag)},t.prototype.makeTag=function(){this.makeId(),this.label&&(this.labels[this.label]=new s(this.currentTag.tag,this.currentTag.tagId));var t=new i.default("\\text{"+this.currentTag.tagFormat+"}",{},this.configuration).mml();return this.configuration.nodeFactory.create("node","mtd",[t],{id:this.currentTag.tagId})},t}();e.AbstractTags=c;var u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.autoTag=function(){},e.prototype.getTag=function(){return this.currentTag.tag?t.prototype.getTag.call(this):null},e}(c);e.NoTags=u;var p=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.finalize=function(t,e){if(!e.display||this.history.find((function(t){return t.taggable})))return t;var r=this.getTag(!0);return this.enTag(t,r)},e}(c);e.AllTags=p,function(t){var e=new Map([["none",u],["all",p]]),r="none";t.OPTIONS={tags:r,tagSide:"right",tagIndent:"0.8em",multlineWidth:"85%",useLabelIds:!0,ignoreDuplicateLabels:!1},t.add=function(t,r){e.set(t,r)},t.addTags=function(e){var r,n;try{for(var o=a(Object.keys(e)),i=o.next();!i.done;i=o.next()){var s=i.value;t.add(s,e[s])}}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}},t.create=function(t){var n=e.get(t)||e.get(r);if(!n)throw Error("Unknown tags class");return new n},t.setDefault=function(t){r=t},t.getDefault=function(){return t.create(r)}}(e.TagsFactory||(e.TagsFactory={}))},7007:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.TexConstant=void 0,function(t){t.Variant={NORMAL:"normal",BOLD:"bold",ITALIC:"italic",BOLDITALIC:"bold-italic",DOUBLESTRUCK:"double-struck",FRAKTUR:"fraktur",BOLDFRAKTUR:"bold-fraktur",SCRIPT:"script",BOLDSCRIPT:"bold-script",SANSSERIF:"sans-serif",BOLDSANSSERIF:"bold-sans-serif",SANSSERIFITALIC:"sans-serif-italic",SANSSERIFBOLDITALIC:"sans-serif-bold-italic",MONOSPACE:"monospace",INITIAL:"inital",TAILED:"tailed",LOOPED:"looped",STRETCHED:"stretched",CALLIGRAPHIC:"-tex-calligraphic",BOLDCALLIGRAPHIC:"-tex-bold-calligraphic",OLDSTYLE:"-tex-oldstyle",BOLDOLDSTYLE:"-tex-bold-oldstyle",MATHITALIC:"-tex-mathit"},t.Form={PREFIX:"prefix",INFIX:"infix",POSTFIX:"postfix"},t.LineBreak={AUTO:"auto",NEWLINE:"newline",NOBREAK:"nobreak",GOODBREAK:"goodbreak",BADBREAK:"badbreak"},t.LineBreakStyle={BEFORE:"before",AFTER:"after",DUPLICATE:"duplicate",INFIXLINBREAKSTYLE:"infixlinebreakstyle"},t.IndentAlign={LEFT:"left",CENTER:"center",RIGHT:"right",AUTO:"auto",ID:"id",INDENTALIGN:"indentalign"},t.IndentShift={INDENTSHIFT:"indentshift"},t.LineThickness={THIN:"thin",MEDIUM:"medium",THICK:"thick"},t.Notation={LONGDIV:"longdiv",ACTUARIAL:"actuarial",PHASORANGLE:"phasorangle",RADICAL:"radical",BOX:"box",ROUNDEDBOX:"roundedbox",CIRCLE:"circle",LEFT:"left",RIGHT:"right",TOP:"top",BOTTOM:"bottom",UPDIAGONALSTRIKE:"updiagonalstrike",DOWNDIAGONALSTRIKE:"downdiagonalstrike",VERTICALSTRIKE:"verticalstrike",HORIZONTALSTRIKE:"horizontalstrike",NORTHEASTARROW:"northeastarrow",MADRUWB:"madruwb",UPDIAGONALARROW:"updiagonalarrow"},t.Align={TOP:"top",BOTTOM:"bottom",CENTER:"center",BASELINE:"baseline",AXIS:"axis",LEFT:"left",RIGHT:"right"},t.Lines={NONE:"none",SOLID:"solid",DASHED:"dashed"},t.Side={LEFT:"left",RIGHT:"right",LEFTOVERLAP:"leftoverlap",RIGHTOVERLAP:"rightoverlap"},t.Width={AUTO:"auto",FIT:"fit"},t.Actiontype={TOGGLE:"toggle",STATUSLINE:"statusline",TOOLTIP:"tooltip",INPUT:"input"},t.Overflow={LINBREAK:"linebreak",SCROLL:"scroll",ELIDE:"elide",TRUNCATE:"truncate",SCALE:"scale"},t.Unit={EM:"em",EX:"ex",PX:"px",IN:"in",CM:"cm",MM:"mm",PT:"pt",PC:"pc"}}(e.TexConstant||(e.TexConstant={}))},3466:function(t,e){Object.defineProperty(e,"__esModule",{value:!0});var r=function(){function t(e,r){for(var n=[],o=2;o="0"&&i<="9")n[o]=r[parseInt(n[o],10)-1],"number"==typeof n[o]&&(n[o]=n[o].toString());else if("{"===i){if((i=n[o].substr(1))>="0"&&i<="9")n[o]=r[parseInt(n[o].substr(1,n[o].length-2),10)-1],"number"==typeof n[o]&&(n[o]=n[o].toString());else n[o].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/)&&(n[o]="%"+n[o])}null==n[o]&&(n[o]="???")}return n.join("")},t.pattern=/%(\d+|\{\d+\}|\{[a-z]+:\%\d+(?:\|(?:%\{\d+\}|%.|[^\}])*)+\}|.)/g,t}();e.default=r},810:function(t,e,r){var n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},a=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0;)u+="rl",p.push("0em 0em"),f--;var d=p.join(" ");if(a)return e.AmsMethods.EqnArray(t,r,o,a,u,d);var h=e.AmsMethods.EqnArray(t,r,o,a,u,d);return n.default.setArrayAlign(h,l)},e.AmsMethods.Multline=function(t,e,r){t.Push(e),n.default.checkEqnEnv(t);var o=t.itemFactory.create("multline",r,t.stack);return o.arraydef={displaystyle:!0,rowspacing:".5em",columnwidth:"100%",width:t.options.multlineWidth,side:t.options.tagSide,minlabelspacing:t.options.tagIndent},o},e.NEW_OPS="ams-declare-ops",e.AmsMethods.HandleDeclareOp=function(t,r){var o=t.GetStar()?"":"\\nolimits\\SkipLimits",a=n.default.trimSpaces(t.GetArgument(r));"\\"===a.charAt(0)&&(a=a.substr(1));var i=t.GetArgument(r);i.match(/\\text/)||(i=i.replace(/\*/g,"\\text{*}").replace(/-/g,"\\text{-}")),t.configuration.handlers.retrieve(e.NEW_OPS).add(a,new l.Macro(a,e.AmsMethods.Macro,["\\mathop{\\rm "+i+"}"+o]))},e.AmsMethods.HandleOperatorName=function(t,e){var r=t.GetStar()?"":"\\nolimits\\SkipLimits",o=n.default.trimSpaces(t.GetArgument(e));o.match(/\\text/)||(o=o.replace(/\*/g,"\\text{*}").replace(/-/g,"\\text{-}")),t.string="\\mathop{\\rm "+o+"}"+r+" "+t.string.slice(t.i),t.i=0},e.AmsMethods.SkipLimits=function(t,e){var r=t.GetNext(),n=t.i;"\\"===r&&++t.i&&"limits"!==t.GetCS()&&(t.i=n)},e.AmsMethods.MultiIntegral=function(t,e,r){var n=t.GetNext();if("\\"===n){var o=t.i;n=t.GetArgument(e),t.i=o,"\\limits"===n&&(r="\\idotsint"===e?"\\!\\!\\mathop{\\,\\,"+r+"}":"\\!\\!\\!\\mathop{\\,\\,\\,"+r+"}")}t.string=r+" "+t.string.slice(t.i),t.i=0},e.AmsMethods.xArrow=function(t,e,r,a,s){var l={width:"+"+n.default.Em((a+s)/18),lspace:n.default.Em(a/18)},c=t.GetBrackets(e),p=t.ParseArg(e),f=t.create("node","mspace",[],{depth:".25em"}),d=t.create("token","mo",{stretchy:!0,texClass:u.TEXCLASS.REL},String.fromCodePoint(r));d=t.create("node","mstyle",[d],{scriptlevel:0});var h=t.create("node","munderover",[d]),m=t.create("node","mpadded",[p,f],l);if(o.default.setAttribute(m,"voffset","-.2em"),o.default.setAttribute(m,"height","-.2em"),o.default.setChild(h,h.over,m),c){var g=new i.default(c,t.stack.env,t.configuration).mml(),y=t.create("node","mspace",[],{height:".75em"});m=t.create("node","mpadded",[g,y],l),o.default.setAttribute(m,"voffset",".15em"),o.default.setAttribute(m,"depth","-.15em"),o.default.setChild(h,h.under,m)}o.default.setProperty(h,"subsupOK",!0),t.Push(h)},e.AmsMethods.HandleShove=function(t,e,r){var n=t.stack.Top();if("multline"!==n.kind)throw new s.default("CommandOnlyAllowedInEnv","%1 only allowed in %2 environment",t.currentCS,"multline");if(n.Size())throw new s.default("CommandAtTheBeginingOfLine","%1 must come at the beginning of the line",t.currentCS);n.setProperty("shove",r)},e.AmsMethods.CFrac=function(t,e){var r=n.default.trimSpaces(t.GetBrackets(e,"")),l=t.GetArgument(e),c=t.GetArgument(e),u={l:a.TexConstant.Align.LEFT,r:a.TexConstant.Align.RIGHT,"":""},p=new i.default("\\strut\\textstyle{"+l+"}",t.stack.env,t.configuration).mml(),f=new i.default("\\strut\\textstyle{"+c+"}",t.stack.env,t.configuration).mml(),d=t.create("node","mfrac",[p,f]);if(null==(r=u[r]))throw new s.default("IllegalAlign","Illegal alignment specified in %1",t.currentCS);r&&o.default.setProperties(d,{numalign:r,denomalign:r}),t.Push(d)},e.AmsMethods.Genfrac=function(t,e,r,a,i,l){null==r&&(r=t.GetDelimiterArg(e)),null==a&&(a=t.GetDelimiterArg(e)),null==i&&(i=t.GetArgument(e)),null==l&&(l=n.default.trimSpaces(t.GetArgument(e)));var c=t.ParseArg(e),u=t.ParseArg(e),p=t.create("node","mfrac",[c,u]);if(""!==i&&o.default.setAttribute(p,"linethickness",i),(r||a)&&(o.default.setProperty(p,"withDelims",!0),p=n.default.fixedFence(t.configuration,r,p,a)),""!==l){var f=parseInt(l,10),d=["D","T","S","SS"][f];if(null==d)throw new s.default("BadMathStyleFor","Bad math style for %1",t.currentCS);p=t.create("node","mstyle",[p]),"D"===d?o.default.setProperties(p,{displaystyle:!0,scriptlevel:0}):o.default.setProperties(p,{displaystyle:!1,scriptlevel:f-1})}t.Push(p)},e.AmsMethods.HandleTag=function(t,e){if(!t.tags.currentTag.taggable&&t.tags.env)throw new s.default("CommandNotAllowedInEnv","%1 not allowed in %2 environment",t.currentCS,t.tags.env);if(t.tags.currentTag.tag)throw new s.default("MultipleCommand","Multiple %1",t.currentCS);var r=t.GetStar(),o=n.default.trimSpaces(t.GetArgument(e));t.tags.tag(o,r)},e.AmsMethods.HandleNoTag=c.default.HandleNoTag,e.AmsMethods.HandleRef=c.default.HandleRef,e.AmsMethods.Macro=c.default.Macro,e.AmsMethods.Accent=c.default.Accent,e.AmsMethods.Tilde=c.default.Tilde,e.AmsMethods.Array=c.default.Array,e.AmsMethods.Spacer=c.default.Spacer,e.AmsMethods.NamedOp=c.default.NamedOp,e.AmsMethods.EqnArray=c.default.EqnArray},6701:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.AmsCdConfiguration=void 0;var n=r(6552);r(7673),e.AmsCdConfiguration=n.Configuration.create("amscd",{handler:{character:["amscd_special"],macro:["amscd_macros"],environment:["amscd_environment"]},options:{amscd:{colspace:"5pt",rowspace:"5pt",harrowsize:"2.75em",varrowsize:"1.75em",hideHorizontalLabels:!1}}})},7673:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(7628),o=r(4708),a=r(7215);new n.EnvironmentMap("amscd_environment",o.default.environment,{CD:"CD"},a.default),new n.CommandMap("amscd_macros",{minCDarrowwidth:"minCDarrowwidth",minCDarrowheight:"minCDarrowheight"},a.default),new n.MacroMap("amscd_special",{"@":"arrow"},a.default)},7215:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(810),o=r(3606),a=r(8921),i=r(8321),s={CD:function(t,e){t.Push(e);var r=t.itemFactory.create("array"),n=t.configuration.options.amscd;return r.setProperties({minw:t.stack.env.CD_minw||n.harrowsize,minh:t.stack.env.CD_minh||n.varrowsize}),r.arraydef={columnalign:"center",columnspacing:n.colspace,rowspacing:n.rowspace,displaystyle:!0},r},arrow:function(t,e){var r=t.string.charAt(t.i);if(!r.match(/[>":"\u2192","<":"\u2190",V:"\u2193",A:"\u2191"}[r],g=t.GetUpTo(e+r,r),y=t.GetUpTo(e+r,r);if(">"===r||"<"===r){if(c=t.create("token","mo",d,m),g||(g="\\kern "+u.getProperty("minw")),g||y){var v={width:".67em",lspace:".33em"};if(c=t.create("node","munderover",[c]),g){var b=new n.default(g,t.stack.env,t.configuration).mml(),x=t.create("node","mpadded",[b],v);i.default.setAttribute(x,"voffset",".1em"),i.default.setChild(c,c.over,x)}if(y){var _=new n.default(y,t.stack.env,t.configuration).mml();i.default.setChild(c,c.under,t.create("node","mpadded",[_],v))}t.configuration.options.amscd.hideHorizontalLabels&&(c=t.create("node","mpadded",c,{depth:0,height:".67em"}))}}else{var A=t.create("token","mo",h,m);c=A,(g||y)&&(c=t.create("node","mrow"),g&&i.default.appendChildren(c,[new n.default("\\scriptstyle\\llap{"+g+"}",t.stack.env,t.configuration).mml()]),A.texClass=a.TEXCLASS.ORD,i.default.appendChildren(c,[A]),y&&i.default.appendChildren(c,[new n.default("\\scriptstyle\\rlap{"+y+"}",t.stack.env,t.configuration).mml()]))}}c&&t.Push(c),s.cell(t,e)},cell:function(t,e){var r=t.stack.Top();(r.table||[]).length%2==0&&0===(r.row||[]).length&&t.Push(t.create("node","mpadded",[],{height:"8.5pt",depth:"2pt"})),t.Push(t.itemFactory.create("cell").setProperties({isEntry:!0,name:e}))},minCDarrowwidth:function(t,e){t.stack.env.CD_minw=t.GetDimen(e)},minCDarrowheight:function(t,e){t.stack.env.CD_minh=t.GetDimen(e)}};e.default=s},1451:function(t,e,r){var n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},o=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.AutoloadConfiguration=void 0;var a=r(6552),i=r(7628),s=r(4237),l=r(4303),c=r(1993),u=r(9077);function p(t,e,r,a){var i,s,u,p;if(c.Package.packages.has(t.options.require.prefix+r)){var h=t.options.autoload[r],m=n(2===h.length&&Array.isArray(h[0])?h:[h,[]],2),g=m[0],y=m[1];try{for(var v=o(g),b=v.next();!b.done;b=v.next()){var x=b.value;f.remove(x)}}catch(t){i={error:t}}finally{try{b&&!b.done&&(s=v.return)&&s.call(v)}finally{if(i)throw i.error}}try{for(var _=o(y),A=_.next();!A.done;A=_.next()){var M=A.value;d.remove(M)}}catch(t){u={error:t}}finally{try{A&&!A.done&&(p=_.return)&&p.call(_)}finally{if(u)throw u.error}}t.string=(a?e+" ":"\\begin{"+e.slice(1)+"}")+t.string.slice(t.i),t.i=0}l.RequireLoad(t,r)}var f=new i.CommandMap("autoload-macros",{},{}),d=new i.CommandMap("autoload-environments",{},{});e.AutoloadConfiguration=a.Configuration.create("autoload",{handler:{macro:["autoload-macros"],environment:["autoload-environments"]},options:{autoload:u.expandable({action:["toggle","mathtip","texttip"],amscd:[[],["CD"]],bbox:["bbox"],boldsymbol:["boldsymbol"],braket:["bra","ket","braket","set","Bra","Ket","Braket","Set","ketbra","Ketbra"],bussproofs:[[],["prooftree"]],cancel:["cancel","bcancel","xcancel","cancelto"],color:["color","definecolor","textcolor","colorbox","fcolorbox"],enclose:["enclose"],extpfeil:["xtwoheadrightarrow","xtwoheadleftarrow","xmapsto","xlongequal","xtofrom","Newextarrow"],html:["href","class","style","cssId"],mhchem:["ce","pu"],newcommand:["newcommand","renewcommand","newenvironment","renewenvironment","def","let"],unicode:["unicode"],verb:["verb"]})},config:function(t,e){var r,a,i,c,u,h,m=e.parseOptions,g=m.handlers.get("macro"),y=m.handlers.get("environment"),v=m.options.autoload;m.packageData.set("autoload",{Autoload:p});try{for(var b=o(Object.keys(v)),x=b.next();!x.done;x=b.next()){var _=x.value,A=v[_],M=n(2===A.length&&Array.isArray(A[0])?A:[A,[]],2),C=M[0],w=M[1];try{for(var S=(i=void 0,o(C)),P=S.next();!P.done;P=S.next()){var T=P.value;g.lookup(T)&&"color"!==T||f.add(T,new s.Macro(T,p,[_,!0]))}}catch(t){i={error:t}}finally{try{P&&!P.done&&(c=S.return)&&c.call(S)}finally{if(i)throw i.error}}try{for(var O=(u=void 0,o(w)),k=O.next();!k.done;k=O.next()){var E=k.value;y.lookup(E)||d.add(E,new s.Macro(E,p,[_,!1]))}}catch(t){u={error:t}}finally{try{k&&!k.done&&(h=O.return)&&h.call(O)}finally{if(u)throw u.error}}}}catch(t){r={error:t}}finally{try{x&&!x.done&&(a=b.return)&&a.call(b)}finally{if(r)throw r.error}}m.packageData.get("require")||l.RequireConfiguration.config(t,e)},init:function(t){t.options.require||u.defaultOptions(t.options,l.RequireConfiguration.options)},priority:10})},3606:function(t,e,r){var n,o,a=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.BaseConfiguration=e.BaseTags=e.Other=void 0;var i=r(6552),s=r(2910),l=r(3466),c=r(8321),u=r(7628),p=r(8389),f=r(7251);function d(t,e){var r=t.stack.env.font?{mathvariant:t.stack.env.font}:{},n=s.MapHandler.getMap("remap").lookup(e),o=t.create("token","mo",r,n?n.char:e);c.default.setProperty(o,"fixStretchy",!0),t.configuration.addNode("fixStretchy",o),t.Push(o)}r(4962),new u.CharacterMap("remap",null,{"-":"\u2212","*":"\u2217","`":"\u2018"}),e.Other=d;var h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return a(e,t),e}(f.AbstractTags);e.BaseTags=h,e.BaseConfiguration=i.Configuration.create("base",{handler:{character:["command","special","letter","digit"],delimiter:["delimiter"],macro:["delimiter","macros","mathchar0mi","mathchar0mo","mathchar7"],environment:["environment"]},fallback:{character:d,macro:function(t,e){throw new l.default("UndefinedControlSequence","Undefined control sequence %1","\\"+e)},environment:function(t,e){throw new l.default("UnknownEnv","Unknown environment '%1'",e)}},items:(o={},o[p.StartItem.prototype.kind]=p.StartItem,o[p.StopItem.prototype.kind]=p.StopItem,o[p.OpenItem.prototype.kind]=p.OpenItem,o[p.CloseItem.prototype.kind]=p.CloseItem,o[p.PrimeItem.prototype.kind]=p.PrimeItem,o[p.SubsupItem.prototype.kind]=p.SubsupItem,o[p.OverItem.prototype.kind]=p.OverItem,o[p.LeftItem.prototype.kind]=p.LeftItem,o[p.Middle.prototype.kind]=p.Middle,o[p.RightItem.prototype.kind]=p.RightItem,o[p.BeginItem.prototype.kind]=p.BeginItem,o[p.EndItem.prototype.kind]=p.EndItem,o[p.StyleItem.prototype.kind]=p.StyleItem,o[p.PositionItem.prototype.kind]=p.PositionItem,o[p.CellItem.prototype.kind]=p.CellItem,o[p.MmlItem.prototype.kind]=p.MmlItem,o[p.FnItem.prototype.kind]=p.FnItem,o[p.NotItem.prototype.kind]=p.NotItem,o[p.DotsItem.prototype.kind]=p.DotsItem,o[p.ArrayItem.prototype.kind]=p.ArrayItem,o[p.EqnArrayItem.prototype.kind]=p.EqnArrayItem,o[p.EquationItem.prototype.kind]=p.EquationItem,o),options:{maxMacros:1e3,baseURL:"undefined"==typeof document||0===document.getElementsByTagName("base").length?"":String(document.location).replace(/#.*$/,"")},tags:{base:h}})},8389:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),a=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},i=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r",succ:"\u227b",prec:"\u227a",approx:"\u2248",succeq:"\u2ab0",preceq:"\u2aaf",supset:"\u2283",subset:"\u2282",supseteq:"\u2287",subseteq:"\u2286",in:"\u2208",ni:"\u220b",notin:"\u2209",owns:"\u220b",gg:"\u226b",ll:"\u226a",sim:"\u223c",simeq:"\u2243",perp:"\u22a5",equiv:"\u2261",asymp:"\u224d",smile:"\u2323",frown:"\u2322",ne:"\u2260",neq:"\u2260",cong:"\u2245",doteq:"\u2250",bowtie:"\u22c8",models:"\u22a8",notChar:"\u29f8",Leftrightarrow:"\u21d4",Leftarrow:"\u21d0",Rightarrow:"\u21d2",leftrightarrow:"\u2194",leftarrow:"\u2190",gets:"\u2190",rightarrow:"\u2192",to:["\u2192",{accent:!1}],mapsto:"\u21a6",leftharpoonup:"\u21bc",leftharpoondown:"\u21bd",rightharpoonup:"\u21c0",rightharpoondown:"\u21c1",nearrow:"\u2197",searrow:"\u2198",nwarrow:"\u2196",swarrow:"\u2199",rightleftharpoons:"\u21cc",hookrightarrow:"\u21aa",hookleftarrow:"\u21a9",longleftarrow:"\u27f5",Longleftarrow:"\u27f8",longrightarrow:"\u27f6",Longrightarrow:"\u27f9",Longleftrightarrow:"\u27fa",longleftrightarrow:"\u27f7",longmapsto:"\u27fc",ldots:"\u2026",cdots:"\u22ef",vdots:"\u22ee",ddots:"\u22f1",dotsc:"\u2026",dotsb:"\u22ef",dotsm:"\u22ef",dotsi:"\u22ef",dotso:"\u2026",ldotp:[".",{texClass:s.TEXCLASS.PUNCT}],cdotp:["\u22c5",{texClass:s.TEXCLASS.PUNCT}],colon:[":",{texClass:s.TEXCLASS.PUNCT}]}),new n.CharacterMap("mathchar7",i.default.mathchar7,{Gamma:"\u0393",Delta:"\u0394",Theta:"\u0398",Lambda:"\u039b",Xi:"\u039e",Pi:"\u03a0",Sigma:"\u03a3",Upsilon:"\u03a5",Phi:"\u03a6",Psi:"\u03a8",Omega:"\u03a9",_:"_","#":"#",$:"$","%":"%","&":"&",And:"&"}),new n.DelimiterMap("delimiter",i.default.delimiter,{"(":"(",")":")","[":"[","]":"]","<":"\u27e8",">":"\u27e9","\\lt":"\u27e8","\\gt":"\u27e9","/":"/","|":["|",{texClass:s.TEXCLASS.ORD}],".":"","\\\\":"\\","\\lmoustache":"\u23b0","\\rmoustache":"\u23b1","\\lgroup":"\u27ee","\\rgroup":"\u27ef","\\arrowvert":"\u23d0","\\Arrowvert":"\u2016","\\bracevert":"\u23aa","\\Vert":["\u2016",{texClass:s.TEXCLASS.ORD}],"\\|":["\u2016",{texClass:s.TEXCLASS.ORD}],"\\vert":["|",{texClass:s.TEXCLASS.ORD}],"\\uparrow":"\u2191","\\downarrow":"\u2193","\\updownarrow":"\u2195","\\Uparrow":"\u21d1","\\Downarrow":"\u21d3","\\Updownarrow":"\u21d5","\\backslash":"\\","\\rangle":"\u27e9","\\langle":"\u27e8","\\rbrace":"}","\\lbrace":"{","\\}":"}","\\{":"{","\\rceil":"\u2309","\\lceil":"\u2308","\\rfloor":"\u230b","\\lfloor":"\u230a","\\lbrack":"[","\\rbrack":"]"}),new n.CommandMap("macros",{displaystyle:["SetStyle","D",!0,0],textstyle:["SetStyle","T",!1,0],scriptstyle:["SetStyle","S",!1,1],scriptscriptstyle:["SetStyle","SS",!1,2],rm:["SetFont",o.TexConstant.Variant.NORMAL],mit:["SetFont",o.TexConstant.Variant.ITALIC],oldstyle:["SetFont",o.TexConstant.Variant.OLDSTYLE],cal:["SetFont",o.TexConstant.Variant.CALLIGRAPHIC],it:["SetFont",o.TexConstant.Variant.MATHITALIC],bf:["SetFont",o.TexConstant.Variant.BOLD],bbFont:["SetFont",o.TexConstant.Variant.DOUBLESTRUCK],scr:["SetFont",o.TexConstant.Variant.SCRIPT],frak:["SetFont",o.TexConstant.Variant.FRAKTUR],sf:["SetFont",o.TexConstant.Variant.SANSSERIF],tt:["SetFont",o.TexConstant.Variant.MONOSPACE],mathrm:["MathFont",o.TexConstant.Variant.NORMAL],mathup:["MathFont",o.TexConstant.Variant.NORMAL],mathnormal:["MathFont",""],mathbf:["MathFont",o.TexConstant.Variant.BOLD],mathbfup:["MathFont",o.TexConstant.Variant.BOLD],mathit:["MathFont",o.TexConstant.Variant.MATHITALIC],mathbfit:["MathFont",o.TexConstant.Variant.BOLDITALIC],mathbb:["MathFont",o.TexConstant.Variant.DOUBLESTRUCK],Bbb:["MathFont",o.TexConstant.Variant.DOUBLESTRUCK],mathfrak:["MathFont",o.TexConstant.Variant.FRAKTUR],mathbffrak:["MathFont",o.TexConstant.Variant.BOLDFRAKTUR],mathscr:["MathFont",o.TexConstant.Variant.SCRIPT],mathbfscr:["MathFont",o.TexConstant.Variant.BOLDSCRIPT],mathsf:["MathFont",o.TexConstant.Variant.SANSSERIF],mathsfup:["MathFont",o.TexConstant.Variant.SANSSERIF],mathbfsf:["MathFont",o.TexConstant.Variant.BOLDSANSSERIF],mathbfsfup:["MathFont",o.TexConstant.Variant.BOLDSANSSERIF],mathsfit:["MathFont",o.TexConstant.Variant.SANSSERIFITALIC],mathbfsfit:["MathFont",o.TexConstant.Variant.SANSSERIFBOLDITALIC],mathtt:["MathFont",o.TexConstant.Variant.MONOSPACE],mathcal:["MathFont",o.TexConstant.Variant.CALLIGRAPHIC],mathbfcal:["MathFont",o.TexConstant.Variant.BOLDCALLIGRAPHIC],symrm:["MathFont",o.TexConstant.Variant.NORMAL],symup:["MathFont",o.TexConstant.Variant.NORMAL],symnormal:["MathFont",""],symbf:["MathFont",o.TexConstant.Variant.BOLD],symbfup:["MathFont",o.TexConstant.Variant.BOLD],symit:["MathFont",o.TexConstant.Variant.ITALIC],symbfit:["MathFont",o.TexConstant.Variant.BOLDITALIC],symbb:["MathFont",o.TexConstant.Variant.DOUBLESTRUCK],symfrak:["MathFont",o.TexConstant.Variant.FRAKTUR],symbffrak:["MathFont",o.TexConstant.Variant.BOLDFRAKTUR],symscr:["MathFont",o.TexConstant.Variant.SCRIPT],symbfscr:["MathFont",o.TexConstant.Variant.BOLDSCRIPT],symsf:["MathFont",o.TexConstant.Variant.SANSSERIF],symsfup:["MathFont",o.TexConstant.Variant.SANSSERIF],symbfsf:["MathFont",o.TexConstant.Variant.BOLDSANSSERIF],symbfsfup:["MathFont",o.TexConstant.Variant.BOLDSANSSERIF],symsfit:["MathFont",o.TexConstant.Variant.SANSSERIFITALIC],symbfsfit:["MathFont",o.TexConstant.Variant.SANSSERIFBOLDITALIC],symtt:["MathFont",o.TexConstant.Variant.MONOSPACE],symcal:["MathFont",o.TexConstant.Variant.CALLIGRAPHIC],symbfcal:["MathFont",o.TexConstant.Variant.BOLDCALLIGRAPHIC],textrm:["HBox",null,o.TexConstant.Variant.NORMAL],textup:["HBox",null,o.TexConstant.Variant.NORMAL],textnormal:["HBox"],textit:["HBox",null,o.TexConstant.Variant.ITALIC],textbf:["HBox",null,o.TexConstant.Variant.BOLD],textsf:["HBox",null,o.TexConstant.Variant.SANSSERIF],texttt:["HBox",null,o.TexConstant.Variant.MONOSPACE],tiny:["SetSize",.5],Tiny:["SetSize",.6],scriptsize:["SetSize",.7],small:["SetSize",.85],normalsize:["SetSize",1],large:["SetSize",1.2],Large:["SetSize",1.44],LARGE:["SetSize",1.73],huge:["SetSize",2.07],Huge:["SetSize",2.49],arcsin:"NamedFn",arccos:"NamedFn",arctan:"NamedFn",arg:"NamedFn",cos:"NamedFn",cosh:"NamedFn",cot:"NamedFn",coth:"NamedFn",csc:"NamedFn",deg:"NamedFn",det:"NamedOp",dim:"NamedFn",exp:"NamedFn",gcd:"NamedOp",hom:"NamedFn",inf:"NamedOp",ker:"NamedFn",lg:"NamedFn",lim:"NamedOp",liminf:["NamedOp","lim inf"],limsup:["NamedOp","lim sup"],ln:"NamedFn",log:"NamedFn",max:"NamedOp",min:"NamedOp",Pr:"NamedOp",sec:"NamedFn",sin:"NamedFn",sinh:"NamedFn",sup:"NamedOp",tan:"NamedFn",tanh:"NamedFn",limits:["Limits",1],nolimits:["Limits",0],overline:["UnderOver","2015"],underline:["UnderOver","2015"],overbrace:["UnderOver","23DE",1],underbrace:["UnderOver","23DF",1],overparen:["UnderOver","23DC"],underparen:["UnderOver","23DD"],overrightarrow:["UnderOver","2192"],underrightarrow:["UnderOver","2192"],overleftarrow:["UnderOver","2190"],underleftarrow:["UnderOver","2190"],overleftrightarrow:["UnderOver","2194"],underleftrightarrow:["UnderOver","2194"],overset:"Overset",underset:"Underset",stackrel:["Macro","\\mathrel{\\mathop{#2}\\limits^{#1}}",2],over:"Over",overwithdelims:"Over",atop:"Over",atopwithdelims:"Over",above:"Over",abovewithdelims:"Over",brace:["Over","{","}"],brack:["Over","[","]"],choose:["Over","(",")"],frac:"Frac",sqrt:"Sqrt",root:"Root",uproot:["MoveRoot","upRoot"],leftroot:["MoveRoot","leftRoot"],left:"LeftRight",right:"LeftRight",middle:"LeftRight",llap:"Lap",rlap:"Lap",raise:"RaiseLower",lower:"RaiseLower",moveleft:"MoveLeftRight",moveright:"MoveLeftRight",",":["Spacer",l.MATHSPACE.thinmathspace],":":["Spacer",l.MATHSPACE.mediummathspace],">":["Spacer",l.MATHSPACE.mediummathspace],";":["Spacer",l.MATHSPACE.thickmathspace],"!":["Spacer",l.MATHSPACE.negativethinmathspace],enspace:["Spacer",.5],quad:["Spacer",1],qquad:["Spacer",2],thinspace:["Spacer",l.MATHSPACE.thinmathspace],negthinspace:["Spacer",l.MATHSPACE.negativethinmathspace],hskip:"Hskip",hspace:"Hskip",kern:"Hskip",mskip:"Hskip",mspace:"Hskip",mkern:"Hskip",rule:"rule",Rule:["Rule"],Space:["Rule","blank"],big:["MakeBig",s.TEXCLASS.ORD,.85],Big:["MakeBig",s.TEXCLASS.ORD,1.15],bigg:["MakeBig",s.TEXCLASS.ORD,1.45],Bigg:["MakeBig",s.TEXCLASS.ORD,1.75],bigl:["MakeBig",s.TEXCLASS.OPEN,.85],Bigl:["MakeBig",s.TEXCLASS.OPEN,1.15],biggl:["MakeBig",s.TEXCLASS.OPEN,1.45],Biggl:["MakeBig",s.TEXCLASS.OPEN,1.75],bigr:["MakeBig",s.TEXCLASS.CLOSE,.85],Bigr:["MakeBig",s.TEXCLASS.CLOSE,1.15],biggr:["MakeBig",s.TEXCLASS.CLOSE,1.45],Biggr:["MakeBig",s.TEXCLASS.CLOSE,1.75],bigm:["MakeBig",s.TEXCLASS.REL,.85],Bigm:["MakeBig",s.TEXCLASS.REL,1.15],biggm:["MakeBig",s.TEXCLASS.REL,1.45],Biggm:["MakeBig",s.TEXCLASS.REL,1.75],mathord:["TeXAtom",s.TEXCLASS.ORD],mathop:["TeXAtom",s.TEXCLASS.OP],mathopen:["TeXAtom",s.TEXCLASS.OPEN],mathclose:["TeXAtom",s.TEXCLASS.CLOSE],mathbin:["TeXAtom",s.TEXCLASS.BIN],mathrel:["TeXAtom",s.TEXCLASS.REL],mathpunct:["TeXAtom",s.TEXCLASS.PUNCT],mathinner:["TeXAtom",s.TEXCLASS.INNER],vcenter:["TeXAtom",s.TEXCLASS.VCENTER],buildrel:"BuildRel",hbox:["HBox",0],text:"HBox",mbox:["HBox",0],fbox:"FBox",strut:"Strut",mathstrut:["Macro","\\vphantom{(}"],phantom:"Phantom",vphantom:["Phantom",1,0],hphantom:["Phantom",0,1],smash:"Smash",acute:["Accent","00B4"],grave:["Accent","0060"],ddot:["Accent","00A8"],tilde:["Accent","007E"],bar:["Accent","00AF"],breve:["Accent","02D8"],check:["Accent","02C7"],hat:["Accent","005E"],vec:["Accent","2192"],dot:["Accent","02D9"],widetilde:["Accent","007E",1],widehat:["Accent","005E",1],matrix:"Matrix",array:"Matrix",pmatrix:["Matrix","(",")"],cases:["Matrix","{","","left left",null,".1em",null,!0],eqalign:["Matrix",null,null,"right left",l.em(l.MATHSPACE.thickmathspace),".5em","D"],displaylines:["Matrix",null,null,"center",null,".5em","D"],cr:"Cr","\\":"CrLaTeX",newline:["CrLaTeX",!0],hline:["HLine","solid"],hdashline:["HLine","dashed"],eqalignno:["Matrix",null,null,"right left",l.em(l.MATHSPACE.thickmathspace),".5em","D",null,"right"],leqalignno:["Matrix",null,null,"right left",l.em(l.MATHSPACE.thickmathspace),".5em","D",null,"left"],hfill:"HFill",hfil:"HFill",hfilll:"HFill",bmod:["Macro",'\\mmlToken{mo}[lspace="thickmathspace" rspace="thickmathspace"]{mod}'],pmod:["Macro","\\pod{\\mmlToken{mi}{mod}\\kern 6mu #1}",1],mod:["Macro","\\mathchoice{\\kern18mu}{\\kern12mu}{\\kern12mu}{\\kern12mu}\\mmlToken{mi}{mod}\\,\\,#1",1],pod:["Macro","\\mathchoice{\\kern18mu}{\\kern8mu}{\\kern8mu}{\\kern8mu}(#1)",1],iff:["Macro","\\;\\Longleftrightarrow\\;"],skew:["Macro","{{#2{#3\\mkern#1mu}\\mkern-#1mu}{}}",3],pmb:["Macro","\\rlap{#1}\\kern1px{#1}",1],TeX:["Macro","T\\kern-.14em\\lower.5ex{E}\\kern-.115em X"],LaTeX:["Macro","L\\kern-.325em\\raise.21em{\\scriptstyle{A}}\\kern-.17em\\TeX"]," ":["Macro","\\text{ }"],not:"Not",dots:"Dots",space:"Tilde","\xa0":"Tilde",begin:"BeginEnd",end:"BeginEnd",label:"HandleLabel",ref:"HandleRef",nonumber:"HandleNoTag",mathchoice:"MathChoice",mmlToken:"MmlToken"},a.default),new n.EnvironmentMap("environment",i.default.environment,{array:["AlignedArray"],equation:["Equation",null,!0],"equation*":["Equation",null,!1],eqnarray:["EqnArray",null,!0,!0,"rcl","0 "+l.em(l.MATHSPACE.thickmathspace),".5em"]},a.default),new n.CharacterMap("not_remap",null,{"\u2190":"\u219a","\u2192":"\u219b","\u2194":"\u21ae","\u21d0":"\u21cd","\u21d2":"\u21cf","\u21d4":"\u21ce","\u2208":"\u2209","\u220b":"\u220c","\u2223":"\u2224","\u2225":"\u2226","\u223c":"\u2241","~":"\u2241","\u2243":"\u2244","\u2245":"\u2247","\u2248":"\u2249","\u224d":"\u226d","=":"\u2260","\u2261":"\u2262","<":"\u226e",">":"\u226f","\u2264":"\u2270","\u2265":"\u2271","\u2272":"\u2274","\u2273":"\u2275","\u2276":"\u2278","\u2277":"\u2279","\u227a":"\u2280","\u227b":"\u2281","\u2282":"\u2284","\u2283":"\u2285","\u2286":"\u2288","\u2287":"\u2289","\u22a2":"\u22ac","\u22a8":"\u22ad","\u22a9":"\u22ae","\u22ab":"\u22af","\u227c":"\u22e0","\u227d":"\u22e1","\u2291":"\u22e2","\u2292":"\u22e3","\u22b2":"\u22ea","\u22b3":"\u22eb","\u22b4":"\u22ec","\u22b5":"\u22ed","\u2203":"\u2204"})},724:function(t,e,r){var n=this&&this.__assign||function(){return(n=Object.assign||function(t){for(var e,r=1,n=arguments.length;r0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(e,"__esModule",{value:!0});var a=r(8389),i=r(8321),s=r(3466),l=r(810),c=r(7007),u=r(7702),p=r(8921),f=r(7251),d=r(6914),h=r(9029),m={},g={fontfamily:1,fontsize:1,fontweight:1,fontstyle:1,color:1,background:1,id:1,class:1,href:1,style:1};function y(t,e){var r=t.stack.env,n=r.inRoot;r.inRoot=!0;var o=new l.default(e,r,t.configuration),a=o.mml(),i=o.stack.global;if(i.leftRoot||i.upRoot){var s={};i.leftRoot&&(s.width=i.leftRoot),i.upRoot&&(s.voffset=i.upRoot,s.height=i.upRoot),a=t.create("node","mpadded",[a],s)}return r.inRoot=n,a}m.Open=function(t,e){t.Push(t.itemFactory.create("open"))},m.Close=function(t,e){t.Push(t.itemFactory.create("close"))},m.Tilde=function(t,e){t.Push(t.create("token","mtext",{},h.entities.nbsp))},m.Space=function(t,e){},m.Superscript=function(t,e){var r,n,a;t.GetNext().match(/\d/)&&(t.string=t.string.substr(0,t.i+1)+" "+t.string.substr(t.i+1));var l=t.stack.Top();l.isKind("prime")?(a=(r=o(l.Peek(2),2))[0],n=r[1],t.stack.Pop()):(a=t.stack.Prev())||(a=t.create("token","mi",{},""));var c=i.default.getProperty(a,"movesupsub"),u=i.default.isType(a,"msubsup")?a.sup:a.over;if(i.default.isType(a,"msubsup")&&!i.default.isType(a,"msup")&&i.default.getChildAt(a,a.sup)||i.default.isType(a,"munderover")&&!i.default.isType(a,"mover")&&i.default.getChildAt(a,a.over)&&!i.default.getProperty(a,"subsupOK"))throw new s.default("DoubleExponent","Double exponent: use braces to clarify");i.default.isType(a,"msubsup")&&!i.default.isType(a,"msup")||(c?((!i.default.isType(a,"munderover")||i.default.isType(a,"mover")||i.default.getChildAt(a,a.over))&&(a=t.create("node","munderover",[a],{movesupsub:!0})),u=a.over):u=(a=t.create("node","msubsup",[a])).sup),t.Push(t.itemFactory.create("subsup",a).setProperties({position:u,primes:n,movesupsub:c}))},m.Subscript=function(t,e){var r,n,a;t.GetNext().match(/\d/)&&(t.string=t.string.substr(0,t.i+1)+" "+t.string.substr(t.i+1));var l=t.stack.Top();l.isKind("prime")?(a=(r=o(l.Peek(2),2))[0],n=r[1],t.stack.Pop()):(a=t.stack.Prev())||(a=t.create("token","mi",{},""));var c=i.default.getProperty(a,"movesupsub"),u=i.default.isType(a,"msubsup")?a.sub:a.under;if(i.default.isType(a,"msubsup")&&!i.default.isType(a,"msup")&&i.default.getChildAt(a,a.sub)||i.default.isType(a,"munderover")&&!i.default.isType(a,"mover")&&i.default.getChildAt(a,a.under)&&!i.default.getProperty(a,"subsupOK"))throw new s.default("DoubleSubscripts","Double subscripts: use braces to clarify");i.default.isType(a,"msubsup")&&!i.default.isType(a,"msup")||(c?((!i.default.isType(a,"munderover")||i.default.isType(a,"mover")||i.default.getChildAt(a,a.under))&&(a=t.create("node","munderover",[a],{movesupsub:!0})),u=a.under):u=(a=t.create("node","msubsup",[a])).sub),t.Push(t.itemFactory.create("subsup",a).setProperties({position:u,primes:n,movesupsub:c}))},m.Prime=function(t,e){var r=t.stack.Prev();if(r||(r=t.create("node","mi")),i.default.isType(r,"msubsup")&&!i.default.isType(r,"msup")&&i.default.getChildAt(r,r.sup))throw new s.default("DoubleExponentPrime","Prime causes double exponent: use braces to clarify");var n="";t.i--;do{n+=h.entities.prime,t.i++,e=t.GetNext()}while("'"===e||e===h.entities.rsquo);n=["","\u2032","\u2033","\u2034","\u2057"][n.length]||n;var o=t.create("token","mo",{variantForm:!0},n);t.Push(t.itemFactory.create("prime",r,o))},m.Comment=function(t,e){for(;t.it.configuration.options.maxMacros)throw new s.default("MaxMacroSub2","MathJax maximum substitution count exceeded; is there a recursive latex environment?");t.parse("environment",[t,r])},m.Array=function(t,e,r,n,o,a,i,s,l){o||(o=t.GetArgument("\\begin{"+e.getName()+"}"));var c=("c"+o).replace(/[^clr|:]/g,"").replace(/[^|:]([|:])+/g,"$1");o=(o=o.replace(/[^clr]/g,"").split("").join(" ")).replace(/l/g,"left").replace(/r/g,"right").replace(/c/g,"center");var u=t.itemFactory.create("array");return u.arraydef={columnalign:o,columnspacing:a||"1em",rowspacing:i||"4pt"},c.match(/[|:]/)&&(c.charAt(0).match(/[|:]/)&&(u.frame.push("left"),u.dashed=":"===c.charAt(0)),c.charAt(c.length-1).match(/[|:]/)&&u.frame.push("right"),c=c.substr(1,c.length-2),u.arraydef.columnlines=c.split("").join(" ").replace(/[^|: ]/g,"none").replace(/\|/g,"solid").replace(/:/g,"dashed")),r&&u.setProperty("open",t.convertDelimiter(r)),n&&u.setProperty("close",t.convertDelimiter(n)),"D"===s?u.arraydef.displaystyle=!0:s&&(u.arraydef.displaystyle=!1),"S"===s&&(u.arraydef.scriptlevel=1),l&&(u.arraydef.useHeight=!1),t.Push(e),u},m.AlignedArray=function(t,e){var r=t.GetBrackets("\\begin{"+e.getName()+"}"),n=m.Array(t,e);return u.default.setArrayAlign(n,r)},m.Equation=function(t,e,r){return t.Push(e),u.default.checkEqnEnv(t),t.itemFactory.create("equation",r).setProperty("name",e.getName())},m.EqnArray=function(t,e,r,n,o,a){t.Push(e),n&&u.default.checkEqnEnv(t),o=(o=o.replace(/[^clr]/g,"").split("").join(" ")).replace(/l/g,"left").replace(/r/g,"right").replace(/c/g,"center");var i=t.itemFactory.create("eqnarray",e.getName(),r,n,t.stack.global);return i.arraydef={displaystyle:!0,columnalign:o,columnspacing:a||"1em",rowspacing:"3pt",side:t.options.tagSide,minlabelspacing:t.options.tagIndent},i},m.HandleNoTag=function(t,e){t.tags.notag()},m.HandleLabel=function(t,e){var r=t.GetArgument(e);if(""!==r&&!t.tags.refUpdate){if(t.tags.label)throw new s.default("MultipleCommand","Multiple %1",t.currentCS);if(t.tags.label=r,(t.tags.allLabels[r]||t.tags.labels[r])&&!t.options.ignoreDuplicateLabels)throw new s.default("MultipleLabel","Label '%1' multiply defined",r);t.tags.labels[r]=new f.Label}},m.HandleRef=function(t,e,r){var n=t.GetArgument(e),o=t.tags.allLabels[n]||t.tags.labels[n];o||(t.tags.refUpdate||(t.tags.redo=!0),o=new f.Label);var a=o.tag;r&&(a=t.tags.formatTag(a));var i=t.create("node","mrow",u.default.internalMath(t,a),{href:t.tags.formatUrl(o.id,t.options.baseURL),class:"MathJax_ref"});t.Push(i)},m.Macro=function(t,e,r,n,o){if(n){var a=[];if(null!=o){var i=t.GetBrackets(e);a.push(null==i?o:i)}for(var l=a.length;lt.configuration.options.maxMacros)throw new s.default("MaxMacroSub1","MathJax maximum macro substitution count exceeded; is there a recursive macro call?")},m.MathChoice=function(t,e){var r=t.ParseArg(e),n=t.ParseArg(e),o=t.ParseArg(e),a=t.ParseArg(e);t.Push(t.create("node","MathChoice",[r,n,o,a]))},e.default=m},3067:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.BboxConfiguration=e.BboxMethods=void 0;var n=r(6552),o=r(7628),a=r(3466);e.BboxMethods={},e.BboxMethods.BBox=function(t,e){for(var r,n,o,l=t.GetBrackets(e,""),c=t.ParseArg(e),u=l.split(/,/),p=0,f=u.length;p=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.BoldsymbolConfiguration=e.rewriteBoldTokens=e.createBoldToken=e.BoldsymbolMethods=void 0;var o=r(6552),a=r(8321),i=r(7007),s=r(7628),l=r(8644),c={};function u(t,e,r,n){var o=l.NodeFactory.createToken(t,e,r,n);return"mtext"!==e&&t.configuration.parser.stack.env.boldsymbol&&(a.default.setProperty(o,"fixBold",!0),t.configuration.addNode("fixBold",o)),o}function p(t){var e,r;try{for(var o=n(t.data.getList("fixBold")),s=o.next();!s.done;s=o.next()){var l=s.value;if(a.default.getProperty(l,"fixBold")){var u=a.default.getAttribute(l,"mathvariant");null==u?a.default.setAttribute(l,"mathvariant",i.TexConstant.Variant.BOLD):a.default.setAttribute(l,"mathvariant",c[u]||u),a.default.removeProperties(l,"fixBold")}}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}}c[i.TexConstant.Variant.NORMAL]=i.TexConstant.Variant.BOLD,c[i.TexConstant.Variant.ITALIC]=i.TexConstant.Variant.BOLDITALIC,c[i.TexConstant.Variant.FRAKTUR]=i.TexConstant.Variant.BOLDFRAKTUR,c[i.TexConstant.Variant.SCRIPT]=i.TexConstant.Variant.BOLDSCRIPT,c[i.TexConstant.Variant.SANSSERIF]=i.TexConstant.Variant.BOLDSANSSERIF,c["-tex-calligraphic"]="-tex-bold-calligraphic",c["-tex-oldstyle"]="-tex-bold-oldstyle",c["-tex-mathit"]=i.TexConstant.Variant.BOLDITALIC,e.BoldsymbolMethods={},e.BoldsymbolMethods.Boldsymbol=function(t,e){var r=t.stack.env.boldsymbol;t.stack.env.boldsymbol=!0;var n=t.ParseArg(e);t.stack.env.boldsymbol=r,t.Push(n)},new s.CommandMap("boldsymbol",{boldsymbol:"Boldsymbol"},e.BoldsymbolMethods),e.createBoldToken=u,e.rewriteBoldTokens=p,e.BoldsymbolConfiguration=o.Configuration.create("boldsymbol",{handler:{macro:["boldsymbol"]},nodes:{token:u},postprocessors:[p]})},1677:function(t,e,r){var n;Object.defineProperty(e,"__esModule",{value:!0}),e.BraketConfiguration=void 0;var o=r(6552),a=r(9365);r(7076),e.BraketConfiguration=o.Configuration.create("braket",{handler:{character:["Braket-characters"],macro:["Braket-macros"]},items:(n={},n[a.BraketItem.prototype.kind]=a.BraketItem,n)})},9365:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.BraketItem=void 0;var a=r(7044),i=r(8921),s=r(7702),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"braket"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isOpen",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.checkItem=function(e){return e.isKind("close")?[[this.factory.create("mml",this.toMml())],!0]:e.isKind("mml")?(this.Push(e.toMml()),this.getProperty("single")?[[this.toMml()],!0]:a.BaseItem.fail):t.prototype.checkItem.call(this,e)},e.prototype.toMml=function(){var e=t.prototype.toMml.call(this),r=this.getProperty("open"),n=this.getProperty("close");if(this.getProperty("stretchy"))return s.default.fenced(this.factory.configuration,r,e,n);var o={fence:!0,stretchy:!1,symmetric:!0,texClass:i.TEXCLASS.OPEN},a=this.create("token","mo",o,r);o.texClass=i.TEXCLASS.CLOSE;var l=this.create("token","mo",o,n);return this.create("node","mrow",[a,e,l],{open:r,close:n,texClass:i.TEXCLASS.INNER})},e}(a.BaseItem);e.BraketItem=l},7076:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(7628),o=r(1990);new n.CommandMap("Braket-macros",{bra:["Macro","{\\langle {#1} \\vert}",1],ket:["Macro","{\\vert {#1} \\rangle}",1],braket:["Braket","\u27e8","\u27e9",!1,1/0],set:["Braket","{","}",!1,1],Bra:["Macro","{\\left\\langle {#1} \\right\\vert}",1],Ket:["Macro","{\\left\\vert {#1} \\right\\rangle}",1],Braket:["Braket","\u27e8","\u27e9",!0,1/0],Set:["Braket","{","}",!0,1],ketbra:["Macro","{\\vert {#1} \\rangle\\langle {#2} \\vert}",2],Ketbra:["Macro","{\\left\\vert {#1} \\right\\rangle\\left\\langle {#2} \\right\\vert}",2],"|":"Bar"},o.default),new n.MacroMap("Braket-characters",{"|":"Bar"},o.default)},1990:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(724),o=r(8921),a=r(3466),i={};i.Macro=n.default.Macro,i.Braket=function(t,e,r,n,o,i){var s=t.GetNext();if(""===s)throw new a.default("MissingArgFor","Missing argument for %1",t.currentCS);var l=!0;"{"===s&&(t.i++,l=!1),t.Push(t.itemFactory.create("braket").setProperties({barmax:i,barcount:0,open:r,close:n,stretchy:o,single:l}))},i.Bar=function(t,e){var r="|"===e?"|":"\u2225",n=t.stack.Top();if("braket"!==n.kind||n.getProperty("barcount")>=n.getProperty("barmax")){var a=t.create("token","mo",{texClass:o.TEXCLASS.ORD,stretchy:!1},r);t.Push(a)}else{if("|"===r&&"|"===t.GetNext()&&(t.i++,r="\u2225"),n.getProperty("stretchy")){var i=t.create("node","TeXAtom",[],{texClass:o.TEXCLASS.CLOSE});t.Push(i),n.setProperty("barcount",n.getProperty("barcount")+1),i=t.create("token","mo",{stretchy:!0,braketbar:!0},r),t.Push(i),i=t.create("node","TeXAtom",[],{texClass:o.TEXCLASS.OPEN}),t.Push(i)}else{var s=t.create("token","mo",{stretchy:!1,braketbar:!0},r);t.Push(s)}}},e.default=i},7404:function(t,e,r){var n;Object.defineProperty(e,"__esModule",{value:!0}),e.BussproofsConfiguration=void 0;var o=r(6552),a=r(2146),i=r(3118);r(1597),e.BussproofsConfiguration=o.Configuration.create("bussproofs",{handler:{macro:["Bussproofs-macros"],environment:["Bussproofs-environments"]},items:(n={},n[a.ProofTreeItem.prototype.kind]=a.ProofTreeItem,n),preprocessors:[[i.saveDocument,1]],postprocessors:[[i.clearDocument,3],[i.makeBsprAttributes,2],[i.balanceRules,1]]})},2146:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.ProofTreeItem=void 0;var a=r(3466),i=r(7044),s=r(9874),l=r(3118),c=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.leftLabel=null,e.rigthLabel=null,e.innerStack=new s.default(e.factory,{},!0),e}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"proofTree"},enumerable:!1,configurable:!0}),e.prototype.checkItem=function(t){if(t.isKind("end")&&"prooftree"===t.getName()){var e=this.toMml();return l.setProperty(e,"proof",!0),[[this.factory.create("mml",e),t],!0]}if(t.isKind("stop"))throw new a.default("EnvMissingEnd","Missing \\end{%1}",this.getName());return this.innerStack.Push(t),i.BaseItem.fail},e.prototype.toMml=function(){var e=t.prototype.toMml.call(this),r=this.innerStack.Top();if(r.isKind("start")&&!r.Size())return e;this.innerStack.Push(this.factory.create("stop"));var n=this.innerStack.Top().toMml();return this.create("node","mrow",[n,e],{})},e}(i.BaseItem);e.ProofTreeItem=c},1597:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(3583),o=r(4708),a=r(7628);new a.CommandMap("Bussproofs-macros",{AxiomC:"Axiom",UnaryInfC:["Inference",1],BinaryInfC:["Inference",2],TrinaryInfC:["Inference",3],QuaternaryInfC:["Inference",4],QuinaryInfC:["Inference",5],RightLabel:["Label","right"],LeftLabel:["Label","left"],AXC:"Axiom",UIC:["Inference",1],BIC:["Inference",2],TIC:["Inference",3],RL:["Label","right"],LL:["Label","left"],noLine:["SetLine","none",!1],singleLine:["SetLine","solid",!1],solidLine:["SetLine","solid",!1],dashedLine:["SetLine","dashed",!1],alwaysNoLine:["SetLine","none",!0],alwaysSingleLine:["SetLine","solid",!0],alwaysSolidLine:["SetLine","solid",!0],alwaysDashedLine:["SetLine","dashed",!0],rootAtTop:["RootAtTop",!0],alwaysRootAtTop:["RootAtTop",!0],rootAtBottom:["RootAtTop",!1],alwaysRootAtBottom:["RootAtTop",!1],fCenter:"FCenter",Axiom:"AxiomF",UnaryInf:["InferenceF",1],BinaryInf:["InferenceF",2],TrinaryInf:["InferenceF",3],QuaternaryInf:["InferenceF",4],QuinaryInf:["InferenceF",5]},n.default),new a.EnvironmentMap("Bussproofs-environments",o.default.environment,{prooftree:["Prooftree",null,!1]},n.default)},3583:function(t,e,r){var n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},o=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r0);var c=t.create("node","mtr",s,{}),f=t.create("node","mtable",[c],{framespacing:"0 0"}),d=u(t,t.GetArgument(e)),h=n.getProperty("currentLine");h!==n.getProperty("line")&&n.setProperty("currentLine",n.getProperty("line"));var m=p(t,f,[d],n.getProperty("left"),n.getProperty("right"),h,o);n.setProperty("left",null),n.setProperty("right",null),l.setProperty(m,"inference",i),t.configuration.addNode("inference",m),n.Push(m)},c.Label=function(t,e,r){var n=t.stack.Top();if("proofTree"!==n.kind)throw new a.default("IllegalProofCommand","Proof commands only allowed in prooftree environment.");var o=s.default.internalMath(t,t.GetArgument(e),0),i=o.length>1?t.create("node","mrow",o,{}):o[0];n.setProperty(r,i)},c.SetLine=function(t,e,r,n){var o=t.stack.Top();if("proofTree"!==o.kind)throw new a.default("IllegalProofCommand","Proof commands only allowed in prooftree environment.");o.setProperty("currentLine",r),n&&o.setProperty("line",r)},c.RootAtTop=function(t,e,r){var n=t.stack.Top();if("proofTree"!==n.kind)throw new a.default("IllegalProofCommand","Proof commands only allowed in prooftree environment.");n.setProperty("rootAtTop",r)},c.AxiomF=function(t,e){var r=t.stack.Top();if("proofTree"!==r.kind)throw new a.default("IllegalProofCommand","Proof commands only allowed in prooftree environment.");var n=f(t,e);l.setProperty(n,"axiom",!0),r.Push(n)},c.FCenter=function(t,e){},c.InferenceF=function(t,e,r){var n=t.stack.Top();if("proofTree"!==n.kind)throw new a.default("IllegalProofCommand","Proof commands only allowed in prooftree environment.");if(n.Size()0);var c=t.create("node","mtr",s,{}),u=t.create("node","mtable",[c],{framespacing:"0 0"}),d=f(t,e),h=n.getProperty("currentLine");h!==n.getProperty("line")&&n.setProperty("currentLine",n.getProperty("line"));var m=p(t,u,[d],n.getProperty("left"),n.getProperty("right"),h,o);n.setProperty("left",null),n.setProperty("right",null),l.setProperty(m,"inference",i),t.configuration.addNode("inference",m),n.Push(m)},e.default=c},3118:function(t,e,r){var n,o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},a=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.clearDocument=e.saveDocument=e.makeBsprAttributes=e.removeProperty=e.getProperty=e.setProperty=e.balanceRules=void 0;var i=r(8321),s=r(7702),l=null,c=null,u=function(t){return c.root=t,l.outputJax.getBBox(c,l).w},p=function(t){for(var e=0;t&&!i.default.isType(t,"mtable");){if(i.default.isType(t,"text"))return null;i.default.isType(t,"mrow")?(t=t.childNodes[0],e=0):(t=t.parent.childNodes[e],e++)}return t},f=function(t,e){return t.childNodes["up"===e?1:0].childNodes[0].childNodes[0].childNodes[0].childNodes[0]},d=function(t,e){return t.childNodes[e].childNodes[0].childNodes[0]},h=function(t){return d(t,0)},m=function(t){return d(t,t.childNodes.length-1)},g=function(t,e){return t.childNodes["up"===e?0:1].childNodes[0].childNodes[0].childNodes[0]},y=function(t){for(;t&&!i.default.isType(t,"mtd");)t=t.parent;return t},v=function(t){return t.parent.childNodes[t.parent.childNodes.indexOf(t)+1]},b=function(t){for(;t&&null==e.getProperty(t,"inference");)t=t.parent;return t},x=function(t,e,r){void 0===r&&(r=!1);var n=0;if(t===e)return n;if(t!==e.parent){var o=t.childNodes,a=r?o.length-1:0;i.default.isType(o[a],"mspace")&&(n+=u(o[a])),t=e.parent}if(t===e)return n;var s=t.childNodes,l=r?s.length-1:0;return s[l]!==e&&(n+=u(s[l])),n},_=function(t,r){void 0===r&&(r=!1);var n=p(t),o=g(n,e.getProperty(n,"inferenceRule"));return x(t,n,r)+(u(n)-u(o))/2},A=function(t,r,n,o){if(void 0===o&&(o=!1),e.getProperty(r,"inferenceRule")||e.getProperty(r,"labelledRule")){var a=t.nodeFactory.create("node","mrow");r.parent.replaceChild(a,r),a.setChildren([r]),M(r,a),r=a}var l=o?r.childNodes.length-1:0,c=r.childNodes[l];i.default.isType(c,"mspace")?i.default.setAttribute(c,"width",s.default.Em(s.default.dimen2em(i.default.getAttribute(c,"width"))+n)):(c=t.nodeFactory.create("node","mspace",[],{width:s.default.Em(n)}),o?r.appendChild(c):(c.parent=r,r.childNodes.unshift(c)))},M=function(t,r){["inference","proof","maxAdjust","labelledRule"].forEach((function(n){var o=e.getProperty(t,n);null!=o&&(e.setProperty(r,n,o),e.removeProperty(t,n))}))},C=function(t,r,n,o,a){var i=t.nodeFactory.create("node","mspace",[],{width:s.default.Em(a)});if("left"===o){var l=r.childNodes[n].childNodes[0];i.parent=l,l.childNodes.unshift(i)}else r.childNodes[n].appendChild(i);e.setProperty(r.parent,"sequentAdjust_"+o,a)},w=function(t,r){for(var n=r.pop();r.length;){var a=r.pop(),i=o(S(n,a),2),s=i[0],l=i[1];e.getProperty(n.parent,"axiom")&&(C(t,s<0?n:a,0,"left",Math.abs(s)),C(t,l<0?n:a,2,"right",Math.abs(l))),n=a}},S=function(t,e){var r=u(t.childNodes[2]),n=u(e.childNodes[2]);return[u(t.childNodes[0])-u(e.childNodes[0]),r-n]};e.balanceRules=function(t){var r,n;c=new t.document.options.MathItem("",null,t.math.display);var o=t.data;!function(t){var r=t.nodeLists.sequent;if(r)for(var n=r.length-1,o=void 0;o=r[n];n--)if(e.getProperty(o,"sequentProcessed"))e.removeProperty(o,"sequentProcessed");else{var a=[],i=b(o);if(1===e.getProperty(i,"inference")){for(a.push(o);1===e.getProperty(i,"inference");){i=p(i);var s=h(f(i,e.getProperty(i,"inferenceRule"))),l=e.getProperty(s,"inferenceRule")?g(s,e.getProperty(s,"inferenceRule")):s;e.getProperty(l,"sequent")&&(o=l.childNodes[0],a.push(o),e.setProperty(o,"sequentProcessed",!0)),i=s}w(t,a)}}}(o);var i=o.nodeLists.inference||[];try{for(var s=a(i),l=s.next();!l.done;l=s.next()){var u=l.value,d=e.getProperty(u,"proof"),M=p(u),C=f(M,e.getProperty(M,"inferenceRule")),S=h(C);if(e.getProperty(S,"inference")){var P=_(S);if(P){A(o,S,-P);var T=x(u,M,!1);A(o,u,P-T)}}var O=m(C);if(null!=e.getProperty(O,"inference")){var k=_(O,!0);A(o,O,-k,!0);var E=x(u,M,!0),I=e.getProperty(u,"maxAdjust");null!=I&&(k=Math.max(k,I));var F=void 0;if(!d&&(F=y(u))){var N=v(F);if(N){var L=o.nodeFactory.create("node","mspace",[],{width:k-E+"em"});N.appendChild(L),u.removeProperty("maxAdjust")}else{var q=b(F);q&&(k=e.getProperty(q,"maxAdjust")?Math.max(e.getProperty(q,"maxAdjust"),k):k,e.setProperty(q,"maxAdjust",k))}}else A(o,e.getProperty(u,"proof")?u:u.parent,k-E,!0)}}}catch(t){r={error:t}}finally{try{l&&!l.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}};var P="bspr_",T=((n={}).bspr_maxAdjust=!0,n);e.setProperty=function(t,e,r){i.default.setProperty(t,P+e,r)};e.getProperty=function(t,e){return i.default.getProperty(t,P+e)};e.removeProperty=function(t,e){t.removeProperty(P+e)};e.makeBsprAttributes=function(t){t.data.root.walkTree((function(t,e){var r=[];t.getPropertyNames().forEach((function(e){!T[e]&&e.match(RegExp("^bspr_"))&&r.push(e+":"+t.getProperty(e))})),r.length&&i.default.setAttribute(t,"semantics",r.join(";"))}))};e.saveDocument=function(t){if(!("getBBox"in(l=t.document).outputJax))throw Error("The bussproofs extension requires an output jax with a getBBox() method")};e.clearDocument=function(t){l=null}},9489:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.CancelConfiguration=e.CancelMethods=void 0;var n=r(6552),o=r(7007),a=r(7628),i=r(7702),s=r(6755);e.CancelMethods={},e.CancelMethods.Cancel=function(t,e,r){var n=t.GetBrackets(e,""),o=t.ParseArg(e),a=i.default.keyvalOptions(n,s.ENCLOSE_OPTIONS);a.notation=r,t.Push(t.create("node","menclose",[o],a))},e.CancelMethods.CancelTo=function(t,e){var r=t.GetBrackets(e,""),n=t.ParseArg(e),a=t.ParseArg(e),l=i.default.keyvalOptions(r,s.ENCLOSE_OPTIONS);l.notation=[o.TexConstant.Notation.UPDIAGONALSTRIKE,o.TexConstant.Notation.UPDIAGONALARROW,o.TexConstant.Notation.NORTHEASTARROW].join(" "),n=t.create("node","mpadded",[n],{depth:"-.1em",height:"+.1em",voffset:".1em"}),t.Push(t.create("node","msup",[t.create("node","menclose",[a],l),n]))},new a.CommandMap("cancel",{cancel:["Cancel",o.TexConstant.Notation.UPDIAGONALSTRIKE],bcancel:["Cancel",o.TexConstant.Notation.DOWNDIAGONALSTRIKE],xcancel:["Cancel",o.TexConstant.Notation.UPDIAGONALSTRIKE+" "+o.TexConstant.Notation.DOWNDIAGONALSTRIKE],cancelto:"CancelTo"},e.CancelMethods),e.CancelConfiguration=n.Configuration.create("cancel",{handler:{macro:["cancel"]}})},4151:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.ColorConfiguration=void 0;var n=r(7628),o=r(6552),a=r(9574),i=r(3997);new n.CommandMap("color",{color:"Color",textcolor:"TextColor",definecolor:"DefineColor",colorbox:"ColorBox",fcolorbox:"FColorBox"},a.ColorMethods);e.ColorConfiguration=o.Configuration.create("color",{handler:{macro:["color"]},options:{color:{padding:"5px",borderWidth:"2px"}},config:function(t,e){e.parseOptions.packageData.set("color",{model:new i.ColorModel})}})},6961:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.COLORS=void 0,e.COLORS=new Map([["Apricot","#FBB982"],["Aquamarine","#00B5BE"],["Bittersweet","#C04F17"],["Black","#221E1F"],["Blue","#2D2F92"],["BlueGreen","#00B3B8"],["BlueViolet","#473992"],["BrickRed","#B6321C"],["Brown","#792500"],["BurntOrange","#F7921D"],["CadetBlue","#74729A"],["CarnationPink","#F282B4"],["Cerulean","#00A2E3"],["CornflowerBlue","#41B0E4"],["Cyan","#00AEEF"],["Dandelion","#FDBC42"],["DarkOrchid","#A4538A"],["Emerald","#00A99D"],["ForestGreen","#009B55"],["Fuchsia","#8C368C"],["Goldenrod","#FFDF42"],["Gray","#949698"],["Green","#00A64F"],["GreenYellow","#DFE674"],["JungleGreen","#00A99A"],["Lavender","#F49EC4"],["LimeGreen","#8DC73E"],["Magenta","#EC008C"],["Mahogany","#A9341F"],["Maroon","#AF3235"],["Melon","#F89E7B"],["MidnightBlue","#006795"],["Mulberry","#A93C93"],["NavyBlue","#006EB8"],["OliveGreen","#3C8031"],["Orange","#F58137"],["OrangeRed","#ED135A"],["Orchid","#AF72B0"],["Peach","#F7965A"],["Periwinkle","#7977B8"],["PineGreen","#008B72"],["Plum","#92268F"],["ProcessBlue","#00B0F0"],["Purple","#99479B"],["RawSienna","#974006"],["Red","#ED1B23"],["RedOrange","#F26035"],["RedViolet","#A1246B"],["Rhodamine","#EF559F"],["RoyalBlue","#0071BC"],["RoyalPurple","#613F99"],["RubineRed","#ED017D"],["Salmon","#F69289"],["SeaGreen","#3FBC9D"],["Sepia","#671800"],["SkyBlue","#46C5DD"],["SpringGreen","#C6DC67"],["Tan","#DA9D76"],["TealBlue","#00AEB3"],["Thistle","#D883B7"],["Turquoise","#00B4CE"],["Violet","#58429B"],["VioletRed","#EF58A0"],["White","#FFFFFF"],["WildStrawberry","#EE2967"],["Yellow","#FFF200"],["YellowGreen","#98CC70"],["YellowOrange","#FAA21A"]])},9574:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.ColorMethods=void 0;var n=r(8321),o=r(7702);function a(t){var e="+"+t,r=t.replace(/^.*?([a-z]*)$/,"$1");return{width:"+"+2*parseFloat(e)+r,height:e,depth:e,lspace:t}}e.ColorMethods={},e.ColorMethods.Color=function(t,e){var r=t.GetBrackets(e,""),n=t.GetArgument(e),o=t.configuration.packageData.get("color").model.getColor(r,n),a=t.itemFactory.create("style").setProperties({styles:{mathcolor:o}});t.stack.env.color=o,t.Push(a)},e.ColorMethods.TextColor=function(t,e){var r=t.GetBrackets(e,""),n=t.GetArgument(e),o=t.configuration.packageData.get("color").model.getColor(r,n),a=t.stack.env.color;t.stack.env.color=o;var i=t.ParseArg(e);a?t.stack.env.color=a:delete t.stack.env.color;var s=t.create("node","mstyle",[i],{mathcolor:o});t.Push(s)},e.ColorMethods.DefineColor=function(t,e){var r=t.GetArgument(e),n=t.GetArgument(e),o=t.GetArgument(e);t.configuration.packageData.get("color").model.defineColor(n,r,o)},e.ColorMethods.ColorBox=function(t,e){var r=t.GetArgument(e),i=o.default.internalMath(t,t.GetArgument(e)),s=t.configuration.packageData.get("color").model,l=t.create("node","mpadded",i,{mathbackground:s.getColor("named",r)});n.default.setProperties(l,a(t.options.color.padding)),t.Push(l)},e.ColorMethods.FColorBox=function(t,e){var r=t.GetArgument(e),i=t.GetArgument(e),s=o.default.internalMath(t,t.GetArgument(e)),l=t.options.color,c=t.configuration.packageData.get("color").model,u=t.create("node","mpadded",s,{mathbackground:c.getColor("named",i),style:"border: "+l.borderWidth+" solid "+c.getColor("named",r)});n.default.setProperties(u,a(l.padding)),t.Push(u)}},3997:function(t,e,r){var n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.ColorModel=void 0;var o=r(3466),a=r(6961),i=new Map,s=function(){function t(){this.userColors=new Map}return t.prototype.normalizeColor=function(t,e){if(!t||"named"===t)return e;if(i.has(t))return i.get(t)(e);throw new o.default("UndefinedColorModel","Color model '%1' not defined",t)},t.prototype.getColor=function(t,e){return t&&"named"!==t?this.normalizeColor(t,e):this.getColorByName(e)},t.prototype.getColorByName=function(t){return this.userColors.has(t)?this.userColors.get(t):a.COLORS.has(t)?a.COLORS.get(t):t},t.prototype.defineColor=function(t,e,r){var n=this.normalizeColor(t,r);this.userColors.set(e,n)},t}();e.ColorModel=s,i.set("rgb",(function(t){var e,r,a=t.trim().split(/\s*,\s*/),i="#";if(3!==a.length)throw new o.default("ModelArg1","Color values for the %1 model require 3 numbers","rgb");try{for(var s=n(a),l=s.next();!l.done;l=s.next()){var c=l.value;if(!c.match(/^(\d+(\.\d*)?|\.\d+)$/))throw new o.default("InvalidDecimalNumber","Invalid decimal number");var u=parseFloat(c);if(u<0||u>1)throw new o.default("ModelArg2","Color values for the %1 model must be between %2 and %3","rgb","0","1");var p=Math.floor(255*u).toString(16);p.length<2&&(p="0"+p),i+=p}}catch(t){e={error:t}}finally{try{l&&!l.done&&(r=s.return)&&r.call(s)}finally{if(e)throw e.error}}return i})),i.set("RGB",(function(t){var e,r,a=t.trim().split(/\s*,\s*/),i="#";if(3!==a.length)throw new o.default("ModelArg1","Color values for the %1 model require 3 numbers","RGB");try{for(var s=n(a),l=s.next();!l.done;l=s.next()){var c=l.value;if(!c.match(/^\d+$/))throw new o.default("InvalidNumber","Invalid number");var u=parseInt(c);if(u>255)throw new o.default("ModelArg2","Color values for the %1 model must be between %2 and %3","RGB","0","255");var p=u.toString(16);p.length<2&&(p="0"+p),i+=p}}catch(t){e={error:t}}finally{try{l&&!l.done&&(r=s.return)&&r.call(s)}finally{if(e)throw e.error}}return i})),i.set("gray",(function(t){if(!t.match(/^\s*(\d+(\.\d*)?|\.\d+)\s*$/))throw new o.default("InvalidDecimalNumber","Invalid decimal number");var e=parseFloat(t);if(e<0||e>1)throw new o.default("ModelArg2","Color values for the %1 model must be between %2 and %3","gray","0","1");var r=Math.floor(255*e).toString(16);return r.length<2&&(r="0"+r),"#"+r+r+r}))},2298:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.ColorConfiguration=e.ColorV2Methods=void 0;var n=r(7628),o=r(6552);e.ColorV2Methods={Color:function(t,e){var r=t.GetArgument(e),n=t.stack.env.color;t.stack.env.color=r;var o=t.ParseArg(e);n?t.stack.env.color=n:delete t.stack.env.color;var a=t.create("node","mstyle",[o],{mathcolor:r});t.Push(a)}},new n.CommandMap("colorv2",{color:"Color"},e.ColorV2Methods),e.ColorConfiguration=o.Configuration.create("colorv2",{handler:{macro:["colorv2"]}})},3274:function(t,e,r){var n,o=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.ConfigMacrosConfiguration=void 0;var a=r(6552),i=r(9077),s=r(7628),l=r(4708),c=r(4237),u=r(8562),p=r(6706),f="configmacros-map",d="configmacros-env-map";e.ConfigMacrosConfiguration=a.Configuration.create("configmacros",{init:function(t){new s.CommandMap(f,{},{}),new s.EnvironmentMap(d,l.default.environment,{},{}),t.append(a.Configuration.local({handler:{macro:[f],environment:[d]},priority:3}))},config:function(t,e){!function(t){var e,r,n=t.parseOptions.handlers.retrieve(f),a=t.parseOptions.options.macros;try{for(var i=o(Object.keys(a)),s=i.next();!s.done;s=i.next()){var l=s.value,p="string"==typeof a[l]?[a[l]]:a[l],d=Array.isArray(p[2])?new c.Macro(l,u.default.MacroWithTemplate,p.slice(0,2).concat(p[2])):new c.Macro(l,u.default.Macro,p);n.add(l,d)}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=i.return)&&r.call(i)}finally{if(e)throw e.error}}}(e),function(t){var e,r,n=t.parseOptions.handlers.retrieve(d),a=t.parseOptions.options.environments;try{for(var i=o(Object.keys(a)),s=i.next();!s.done;s=i.next()){var l=s.value;n.add(l,new c.Macro(l,u.default.BeginEnv,[!0].concat(a[l])))}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=i.return)&&r.call(i)}finally{if(e)throw e.error}}}(e)},items:(n={},n[p.BeginEnvItem.prototype.kind]=p.BeginEnvItem,n),options:{macros:i.expandable({}),environments:i.expandable({})}})},6755:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.EncloseConfiguration=e.EncloseMethods=e.ENCLOSE_OPTIONS=void 0;var n=r(6552),o=r(7628),a=r(7702);e.ENCLOSE_OPTIONS={"data-arrowhead":1,color:1,mathcolor:1,background:1,mathbackground:1,"data-padding":1,"data-thickness":1},e.EncloseMethods={},e.EncloseMethods.Enclose=function(t,r){var n=t.GetArgument(r).replace(/,/g," "),o=t.GetBrackets(r,""),i=t.ParseArg(r),s=a.default.keyvalOptions(o,e.ENCLOSE_OPTIONS);s.notation=n,t.Push(t.create("node","menclose",[i],s))},new o.CommandMap("enclose",{enclose:"Enclose"},e.EncloseMethods),e.EncloseConfiguration=n.Configuration.create("enclose",{handler:{macro:["enclose"]}})},5246:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.ExtpfeilConfiguration=e.ExtpfeilMethods=void 0;var n=r(6552),o=r(7628),a=r(2684),i=r(5282),s=r(2200),l=r(3466);e.ExtpfeilMethods={},e.ExtpfeilMethods.xArrow=a.AmsMethods.xArrow,e.ExtpfeilMethods.NewExtArrow=function(t,r){var n=t.GetArgument(r),o=t.GetArgument(r),a=t.GetArgument(r);if(!n.match(/^\\([a-z]+|.)$/i))throw new l.default("NewextarrowArg1","First argument to %1 must be a control sequence name",r);if(!o.match(/^(\d+),(\d+)$/))throw new l.default("NewextarrowArg2","Second argument to %1 must be two integers separated by a comma",r);if(!a.match(/^(\d+|0x[0-9A-F]+)$/i))throw new l.default("NewextarrowArg3","Third argument to %1 must be a unicode character number",r);n=n.substr(1);var s=o.split(",");i.default.addMacro(t,n,e.ExtpfeilMethods.xArrow,[parseInt(a),parseInt(s[0]),parseInt(s[1])])},new o.CommandMap("extpfeil",{xtwoheadrightarrow:["xArrow",8608,12,16],xtwoheadleftarrow:["xArrow",8606,17,13],xmapsto:["xArrow",8614,6,7],xlongequal:["xArrow",61,7,7],xtofrom:["xArrow",8644,12,12],Newextarrow:"NewExtArrow"},e.ExtpfeilMethods);e.ExtpfeilConfiguration=n.Configuration.create("extpfeil",{handler:{macro:["extpfeil"]},init:function(t){s.NewcommandConfiguration.init(t)}})},153:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.HtmlConfiguration=void 0;var n=r(6552),o=r(7628),a=r(2565);new o.CommandMap("html_macros",{href:"Href",class:"Class",style:"Style",cssId:"Id"},a.default),e.HtmlConfiguration=n.Configuration.create("html",{handler:{macro:["html_macros"]}})},2565:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(8321),o={Href:function(t,e){var r=t.GetArgument(e),o=a(t,e);n.default.setAttribute(o,"href",r),t.Push(o)},Class:function(t,e){var r=t.GetArgument(e),o=a(t,e),i=n.default.getAttribute(o,"class");i&&(r=i+" "+r),n.default.setAttribute(o,"class",r),t.Push(o)},Style:function(t,e){var r=t.GetArgument(e),o=a(t,e),i=n.default.getAttribute(o,"style");i&&(";"!==r.charAt(r.length-1)&&(r+=";"),r=i+" "+r),n.default.setAttribute(o,"style",r),t.Push(o)},Id:function(t,e){var r=t.GetArgument(e),o=a(t,e);n.default.setAttribute(o,"id",r),t.Push(o)}},a=function(t,e){var r=t.ParseArg(e);if(!n.default.isInferred(r))return r;var o=n.default.getChildren(r);if(1===o.length)return o[0];var a=t.create("node","mrow");return n.default.copyChildren(r,a),n.default.copyAttributes(r,a),a};e.default=o},1323:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.MhchemConfiguration=void 0;var n=r(6552),o=r(7628),a=r(3466),i=r(724),s=r(2684),l=r(7552),c={};c.Macro=i.default.Macro,c.xArrow=s.AmsMethods.xArrow,c.Machine=function(t,e,r){try{var n=t.GetArgument(e),o=l.mhchemParser.toTex(n,r);t.string=o+t.string.substr(t.i),t.i=0}catch(t){throw new a.default(t[0],t[1],t.slice(2))}},new o.CommandMap("mhchem",{ce:["Machine","ce"],pu:["Machine","pu"],longrightleftharpoons:["Macro","\\stackrel{\\textstyle{-}\\!\\!{\\rightharpoonup}}{\\smash{{\\leftharpoondown}\\!\\!{-}}}"],longRightleftharpoons:["Macro","\\stackrel{\\textstyle{-}\\!\\!{\\rightharpoonup}}{\\smash{\\leftharpoondown}}"],longLeftrightharpoons:["Macro","\\stackrel{\\textstyle\\vphantom{{-}}{\\rightharpoonup}}{\\smash{{\\leftharpoondown}\\!\\!{-}}}"],longleftrightarrows:["Macro","\\stackrel{\\longrightarrow}{\\smash{\\longleftarrow}\\Rule{0px}{.25em}{0px}}"],tripledash:["Macro","\\vphantom{-}\\raise2mu{\\kern2mu\\tiny\\text{-}\\kern1mu\\text{-}\\kern1mu\\text{-}\\kern2mu}"],xrightarrow:["xArrow",8594,5,6],xleftarrow:["xArrow",8592,7,3],xleftrightarrow:["xArrow",8596,6,6],xrightleftharpoons:["xArrow",8652,5,7],xRightleftharpoons:["xArrow",8652,5,7],xLeftrightharpoons:["xArrow",8652,5,7]},c),e.MhchemConfiguration=n.Configuration.create("mhchem",{handler:{macro:["mhchem"]}})},7552:function(t,e){ +/*! + ************************************************************************* + * + * mhchemParser.ts + * 4.0.0 + * + * Parser for the \ce command and \pu command for MathJax and Co. + * + * mhchem's \ce is a tool for writing beautiful chemical equations easily. + * mhchem's \pu is a tool for writing physical units easily. + * + * ---------------------------------------------------------------------- + * + * Copyright (c) 2015-2021 Martin Hensel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * https://github.com/mhchem/mhchemParser + * + */ +Object.defineProperty(e,"__esModule",{value:!0}),e.mhchemParser=void 0;var r=function(){function t(){}return t.toTex=function(t,e){return a.go(o.go(t,e),"tex"!==e)},t}();function n(t){var e,r,n={};for(e in t)for(r in t[e]){var o=r.split("|");t[e][r].stateArray=o;for(var a=0;a0))return s;if(f.revisit||(t=p.remainder),!f.toContinue)break t}}if(i<=0)throw["MhchemBugU","mhchem bug U. Please report."]}},concatArray:function(t,e){if(e)if(Array.isArray(e))for(var r=0;r":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(t){return o.patterns.findObserveGroups(t,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(t){return o.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",!0)},"\\x{}":function(t){return o.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\color{","","","}")},"\\color{(...)}{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\color{","","","}","{","","","}")||o.patterns.findObserveGroups(t,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\ce{","","","}")},"\\pu{(...)}":function(t){return o.patterns.findObserveGroups(t,"\\pu{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(t){var e;if(e=t.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/))return{match_:e[0],remainder:t.substr(e[0].length)};var r=o.patterns.findObserveGroups(t,"","$","$","");return r&&(e=r.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/))?{match_:e[0],remainder:t.substr(e[0].length)}:null},amount2:function(t){return this.amount(t)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(t){if(t.match(/^\([a-z]+\)$/))return null;var e=t.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);return e?{match_:e[0],remainder:t.substr(e[0].length)}:null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(t,e,r,n,o,a,i,s,l,c){var u=function(t,e){if("string"==typeof e)return 0!==t.indexOf(e)?null:e;var r=t.match(e);return r?r[0]:null},p=u(t,e);if(null===p)return null;if(t=t.substr(p.length),null===(p=u(t,r)))return null;var f=function(t,e,r){for(var n=0;e2?{match_:n.slice(1),remainder:e.substr(n[0].length)}:{match_:n[1]||n[0],remainder:e.substr(n[0].length)}:null}},actions:{"a=":function(t,e){t.a=(t.a||"")+e},"b=":function(t,e){t.b=(t.b||"")+e},"p=":function(t,e){t.p=(t.p||"")+e},"o=":function(t,e){t.o=(t.o||"")+e},"q=":function(t,e){t.q=(t.q||"")+e},"d=":function(t,e){t.d=(t.d||"")+e},"rm=":function(t,e){t.rm=(t.rm||"")+e},"text=":function(t,e){t.text_=(t.text_||"")+e},insert:function(t,e,r){return{type_:r}},"insert+p1":function(t,e,r){return{type_:r,p1:e}},"insert+p1+p2":function(t,e,r){return{type_:r,p1:e[0],p2:e[1]}},copy:function(t,e){return e},write:function(t,e,r){return r},rm:function(t,e){return{type_:"rm",p1:e}},text:function(t,e){return o.go(e,"text")},"tex-math":function(t,e){return o.go(e,"tex-math")},"tex-math tight":function(t,e){return o.go(e,"tex-math tight")},bond:function(t,e,r){return{type_:"bond",kind_:r||e}},"color0-output":function(t,e){return{type_:"color0",color:e}},ce:function(t,e){return o.go(e,"ce")},pu:function(t,e){return o.go(e,"pu")},"1/2":function(t,e){var r=[];e.match(/^[+\-]/)&&(r.push(e.substr(0,1)),e=e.substr(1));var n=e.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);return n[1]=n[1].replace(/\$/g,""),r.push({type_:"frac",p1:n[1],p2:n[2]}),n[3]&&(n[3]=n[3].replace(/\$/g,""),r.push({type_:"tex-math",p1:n[3]})),r},"9,9":function(t,e){return o.go(e,"9,9")}},stateMachines:{tex:{transitions:n({empty:{0:{action_:"copy"}},"\\ce{(...)}":{0:{action_:[{type_:"write",option:"{"},"ce",{type_:"write",option:"}"}]}},"\\pu{(...)}":{0:{action_:[{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},else:{0:{action_:"copy"}}}),actions:{}},ce:{transitions:n({empty:{"*":{action_:"output"}},else:{"0|1|2":{action_:"beginsWithBond=false",revisit:!0,toContinue:!0}},oxidation$:{0:{action_:"oxidation-output"}},CMT:{r:{action_:"rdt=",nextState:"rt"},rd:{action_:"rqt=",nextState:"rdt"}},arrowUpDown:{"0|1|2|as":{action_:["sb=false","output","operator"],nextState:"1"}},uprightEntities:{"0|1|2":{action_:["o=","output"],nextState:"1"}},orbital:{"0|1|2|3":{action_:"o=",nextState:"o"}},"->":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:!1},nextState:"2"},q:{action_:{type_:"- after o/d",option:!1},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:!0},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{action_:[]}},space:{a:{action_:[],nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". __* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{action_:[]}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\pu{(...)}":{"*":{action_:["output",{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}],nextState:"3"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:!0},as:{action_:["output","sb=true"],nextState:"1",revisit:!0},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:!0},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(t,e){var r;if((t.d||"").match(/^[0-9]+$/)){var n=t.d;t.d=void 0,r=this.output(t),t.b=n}else r=this.output(t);return o.actions["o="](t,e),r},"d= kv":function(t,e){t.d=e,t.dType="kv"},"charge or bond":function(t,e){if(t.beginsWithBond){var r=[];return o.concatArray(r,this.output(t)),o.concatArray(r,o.actions.bond(t,e,"-")),r}t.d=e},"- after o/d":function(t,e,r){var n=o.patterns.match_("orbital",t.o||""),a=o.patterns.match_("one lowercase greek letter $",t.o||""),i=o.patterns.match_("one lowercase latin letter $",t.o||""),s=o.patterns.match_("$one lowercase latin letter$ $",t.o||""),l="-"===e&&(n&&""===n.remainder||a||i||s);!l||t.a||t.b||t.p||t.d||t.q||n||!i||(t.o="$"+t.o+"$");var c=[];return l?(o.concatArray(c,this.output(t)),c.push({type_:"hyphen"})):(n=o.patterns.match_("digits",t.d||""),r&&n&&""===n.remainder?(o.concatArray(c,o.actions["d="](t,e)),o.concatArray(c,this.output(t))):(o.concatArray(c,this.output(t)),o.concatArray(c,o.actions.bond(t,e,"-")))),c},"a to o":function(t){t.o=t.a,t.a=void 0},"sb=true":function(t){t.sb=!0},"sb=false":function(t){t.sb=!1},"beginsWithBond=true":function(t){t.beginsWithBond=!0},"beginsWithBond=false":function(t){t.beginsWithBond=!1},"parenthesisLevel++":function(t){t.parenthesisLevel++},"parenthesisLevel--":function(t){t.parenthesisLevel--},"state of aggregation":function(t,e){return{type_:"state of aggregation",p1:o.go(e,"o")}},comma:function(t,e){var r=e.replace(/\s*$/,"");return r!==e&&0===t.parenthesisLevel?{type_:"comma enumeration L",p1:r}:{type_:"comma enumeration M",p1:r}},output:function(t,e,r){var n;if(t.r){var a=void 0;a="M"===t.rdt?o.go(t.rd,"tex-math"):"T"===t.rdt?[{type_:"text",p1:t.rd||""}]:o.go(t.rd,"ce");var i=void 0;i="M"===t.rqt?o.go(t.rq,"tex-math"):"T"===t.rqt?[{type_:"text",p1:t.rq||""}]:o.go(t.rq,"ce"),n={type_:"arrow",r:t.r,rd:a,rq:i}}else n=[],(t.a||t.b||t.p||t.o||t.q||t.d||r)&&(t.sb&&n.push({type_:"entitySkip"}),t.o||t.q||t.d||t.b||t.p||2===r?t.o||t.q||t.d||!t.b&&!t.p?t.o&&"kv"===t.dType&&o.patterns.match_("d-oxidation$",t.d||"")?t.dType="oxidation":t.o&&"kv"===t.dType&&!t.q&&(t.dType=void 0):(t.o=t.a,t.d=t.b,t.q=t.p,t.a=t.b=t.p=void 0):(t.o=t.a,t.a=void 0),n.push({type_:"chemfive",a:o.go(t.a,"a"),b:o.go(t.b,"bd"),p:o.go(t.p,"pq"),o:o.go(t.o,"o"),q:o.go(t.q,"pq"),d:o.go(t.d,"oxidation"===t.dType?"oxidation":"bd"),dType:t.dType}));for(var s in t)"parenthesisLevel"!==s&&"beginsWithBond"!==s&&delete t[s];return n},"oxidation-output":function(t,e){var r=["{"];return o.concatArray(r,o.go(e,"oxidation")),r.push("}"),r},"frac-output":function(t,e){return{type_:"frac-ce",p1:o.go(e[0],"ce"),p2:o.go(e[1],"ce")}},"overset-output":function(t,e){return{type_:"overset",p1:o.go(e[0],"ce"),p2:o.go(e[1],"ce")}},"underset-output":function(t,e){return{type_:"underset",p1:o.go(e[0],"ce"),p2:o.go(e[1],"ce")}},"underbrace-output":function(t,e){return{type_:"underbrace",p1:o.go(e[0],"ce"),p2:o.go(e[1],"ce")}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:o.go(e[1],"ce")}},"r=":function(t,e){t.r=e},"rdt=":function(t,e){t.rdt=e},"rd=":function(t,e){t.rd=e},"rqt=":function(t,e){t.rqt=e},"rq=":function(t,e){t.rq=e},operator:function(t,e,r){return{type_:"operator",kind_:r||e}}}},a:{transitions:n({empty:{"*":{action_:[]}},"1/2$":{0:{action_:"1/2"}},else:{0:{action_:[],nextState:"1",revisit:!0}},"${(...)}$__$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:n({empty:{"*":{action_:[]}},"1/2$":{0:{action_:"1/2"}},else:{0:{action_:[],nextState:"1",revisit:!0}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\pu{(...)}":{"*":{action_:[{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$__$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:[{type_:"write",option:"{"},"text",{type_:"write",option:"}"}]}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:n({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$__$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\pu{(...)}":{"*":{action_:["output",{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(t){if(t.text_){var e={type_:"text",p1:t.text_};for(var r in t)delete t[r];return e}}}},pq:{transitions:n({empty:{"*":{action_:[]}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{action_:[],nextState:"!f",revisit:!0}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{action_:[],nextState:"f",revisit:!0}},"1/2$":{0:{action_:"1/2"}},else:{0:{action_:[],nextState:"!f",revisit:!0}},"${(...)}$__$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}":{"*":{action_:"color-output"}},"\\color{(...)}":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\pu{(...)}":{"*":{action_:[{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(t,e){return{type_:"state of aggregation subscript",p1:o.go(e,"o")}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:o.go(e[1],"pq")}}}},bd:{transitions:n({empty:{"*":{action_:[]}},x$:{0:{action_:[],nextState:"!f",revisit:!0}},formula$:{0:{action_:[],nextState:"f",revisit:!0}},else:{0:{action_:[],nextState:"!f",revisit:!0}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$__$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}":{"*":{action_:"color-output"}},"\\color{(...)}":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\pu{(...)}":{"*":{action_:[{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(t,e){return{type_:"color",color1:e[0],color2:o.go(e[1],"bd")}}}},oxidation:{transitions:n({empty:{"*":{action_:[]}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$__$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(t,e){return{type_:"roman numeral",p1:e}}}},"tex-math":{transitions:n({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"\\pu{(...)}":{"*":{action_:["output",{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var r in t)delete t[r];return e}}}},"tex-math tight":{transitions:n({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"\\pu{(...)}":{"*":{action_:["output",{type_:"write",option:"{"},"pu",{type_:"write",option:"}"}]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(t,e){t.o=(t.o||"")+"{"+e+"}"},output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var r in t)delete t[r];return e}}}},"9,9":{transitions:n({empty:{"*":{action_:[]}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return{type_:"commaDecimal"}}}},pu:{transitions:n({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{action_:[]}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(t,e){var r=[];return"+-"===e[0]||"+/-"===e[0]?r.push("\\pm "):e[0]&&r.push(e[0]),e[1]&&(o.concatArray(r,o.go(e[1],"pu-9,9")),e[2]&&(e[2].match(/[,.]/)?o.concatArray(r,o.go(e[2],"pu-9,9")):r.push(e[2])),(e[3]||e[4])&&("e"===e[3]||"*"===e[4]?r.push({type_:"cdot"}):r.push({type_:"times"}))),e[5]&&r.push("10^{"+e[5]+"}"),r},"number^":function(t,e){var r=[];return"+-"===e[0]||"+/-"===e[0]?r.push("\\pm "):e[0]&&r.push(e[0]),o.concatArray(r,o.go(e[1],"pu-9,9")),r.push("^{"+e[2]+"}"),r},operator:function(t,e,r){return{type_:"operator",kind_:r||e}},space:function(){return{type_:"pu-space-1"}},output:function(t){var e,r=o.patterns.match_("{(...)}",t.d||"");r&&""===r.remainder&&(t.d=r.match_);var n=o.patterns.match_("{(...)}",t.q||"");if(n&&""===n.remainder&&(t.q=n.match_),t.d&&(t.d=t.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.d=t.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F")),t.q){t.q=t.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.q=t.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");var a={d:o.go(t.d,"pu"),q:o.go(t.q,"pu")};"//"===t.o?e={type_:"pu-frac",p1:a.d,p2:a.q}:(e=a.d,a.d.length>1||a.q.length>1?e.push({type_:" / "}):e.push({type_:"/"}),o.concatArray(e,a.q))}else e=o.go(t.d,"pu-2");for(var i in t)delete t[i];return e}}},"pu-2":{transitions:n({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return{type_:"tight cdot"}},"^(-1)":function(t,e){t.rm+="^{"+e+"}"},space:function(){return{type_:"pu-space-2"}},output:function(t){var e=[];if(t.rm){var r=o.patterns.match_("{(...)}",t.rm||"");e=r&&""===r.remainder?o.go(r.match_,"pu"):{type_:"rm",p1:t.rm}}for(var n in t)delete t[n];return e}}},"pu-9,9":{transitions:n({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return{type_:"commaDecimal"}},"output-0":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){var r=t.text_.length%3;0===r&&(r=3);for(var n=t.text_.length-3;n>0;n-=3)e.push(t.text_.substr(n,3)),e.push({type_:"1000 separator"});e.push(t.text_.substr(0,r)),e.reverse()}else e.push(t.text_);for(var o in t)delete t[o];return e},"output-o":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){var r=t.text_.length-3,n=void 0;for(n=0;n"===t.r||"<=>>"===t.r||"<<=>"===t.r||"<--\x3e"===t.r?(s="\\long"+s,i.rd&&(s="\\overset{"+i.rd+"}{"+s+"}"),i.rq&&(s="<--\x3e"===t.r?"\\underset{\\lower2mu{"+i.rq+"}}{"+s+"}":"\\underset{\\lower6mu{"+i.rq+"}}{"+s+"}"),s=" {}\\mathrel{"+s+"}{} "):(i.rq&&(s+="[{"+i.rq+"}]"),s=" {}\\mathrel{\\x"+(s+="{"+i.rd+"}")+"}{} "):s=" {}\\mathrel{\\long"+s+"}{} ",e=s;break;case"operator":e=a._getOperator(t.kind_);break;case"1st-level escape":e=t.p1+" ";break;case"space":e=" ";break;case"entitySkip":case"pu-space-1":e="~";break;case"pu-space-2":e="\\mkern3mu ";break;case"1000 separator":e="\\mkern2mu ";break;case"commaDecimal":e="{,}";break;case"comma enumeration L":e="{"+t.p1+"}\\mkern6mu ";break;case"comma enumeration M":e="{"+t.p1+"}\\mkern3mu ";break;case"comma enumeration S":e="{"+t.p1+"}\\mkern1mu ";break;case"hyphen":e="\\text{-}";break;case"addition compound":e="\\,{\\cdot}\\,";break;case"electron dot":e="\\mkern1mu \\bullet\\mkern1mu ";break;case"KV x":e="{\\times}";break;case"prime":e="\\prime ";break;case"cdot":e="\\cdot ";break;case"tight cdot":e="\\mkern1mu{\\cdot}\\mkern1mu ";break;case"times":e="\\times ";break;case"circa":e="{\\sim}";break;case"^":e="uparrow";break;case"v":e="downarrow";break;case"ellipsis":e="\\ldots ";break;case"/":e="/";break;case" / ":e="\\,/\\,";break;default:throw["MhchemBugT","mhchem bug T. Please report."]}return e},_getArrow:function(t){switch(t){case"->":case"\u2192":case"\u27f6":return"rightarrow";case"<-":return"leftarrow";case"<->":return"leftrightarrow";case"<--\x3e":return"leftrightarrows";case"<=>":case"\u21cc":return"rightleftharpoons";case"<=>>":return"Rightleftharpoons";case"<<=>":return"Leftrightharpoons";default:throw["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(t){switch(t){case"-":case"1":return"{-}";case"=":case"2":return"{=}";case"#":case"3":return"{\\equiv}";case"~":return"{\\tripledash}";case"~-":return"{\\rlap{\\lower.1em{-}}\\raise.1em{\\tripledash}}";case"~=":case"~--":return"{\\rlap{\\lower.2em{-}}\\rlap{\\raise.2em{\\tripledash}}-}";case"-~-":return"{\\rlap{\\lower.2em{-}}\\rlap{\\raise.2em{-}}\\tripledash}";case"...":return"{{\\cdot}{\\cdot}{\\cdot}}";case"....":return"{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case"->":return"{\\rightarrow}";case"<-":return"{\\leftarrow}";case"<":return"{<}";case">":return"{>}";default:throw["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(t){switch(t){case"+":return" {}+{} ";case"-":return" {}-{} ";case"=":return" {}={} ";case"<":return" {}<{} ";case">":return" {}>{} ";case"<<":return" {}\\ll{} ";case">>":return" {}\\gg{} ";case"\\pm":return" {}\\pm{} ";case"\\approx":case"$\\approx$":return" {}\\approx{} ";case"v":case"(v)":return" \\downarrow{} ";case"^":case"(^)":return" \\uparrow{} ";default:throw["MhchemBugT","mhchem bug T. Please report."]}}}},2200:function(t,e,r){var n;Object.defineProperty(e,"__esModule",{value:!0}),e.NewcommandConfiguration=void 0;var o=r(6552),a=r(6706),i=r(5282);r(6823);var s=r(4708),l=r(7628);e.NewcommandConfiguration=o.Configuration.create("newcommand",{handler:{macro:["Newcommand-macros"]},items:(n={},n[a.BeginEnvItem.prototype.kind]=a.BeginEnvItem,n),options:{maxMacros:1e3},init:function(t){new l.DelimiterMap(i.default.NEW_DELIMITER,s.default.delimiter,{}),new l.CommandMap(i.default.NEW_COMMAND,{},{}),new l.EnvironmentMap(i.default.NEW_ENVIRONMENT,s.default.environment,{},{}),t.append(o.Configuration.local({handler:{character:[],delimiter:[i.default.NEW_DELIMITER],macro:[i.default.NEW_DELIMITER,i.default.NEW_COMMAND],environment:[i.default.NEW_ENVIRONMENT]},priority:-1}))}})},6706:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.BeginEnvItem=void 0;var a=r(3466),i=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"beginEnv"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isOpen",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.checkItem=function(e){if(e.isKind("end")){if(e.getName()!==this.getName())throw new a.default("EnvBadEnd","\\begin{%1} ended with \\end{%2}",this.getName(),e.getName());return[[this.factory.create("mml",this.toMml())],!0]}if(e.isKind("stop"))throw new a.default("EnvMissingEnd","Missing \\end{%1}",this.getName());return t.prototype.checkItem.call(this,e)},e}(r(7044).BaseItem);e.BeginEnvItem=i},6823:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(8562);new(r(7628).CommandMap)("Newcommand-macros",{newcommand:"NewCommand",renewcommand:"NewCommand",newenvironment:"NewEnvironment",renewenvironment:"NewEnvironment",def:"MacroDef",let:"Let"},n.default)},8562:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(3466),o=r(7628),a=r(724),i=r(7702),s=r(5282),l={NewCommand:function(t,e){var r=i.default.trimSpaces(t.GetArgument(e)),o=t.GetBrackets(e),a=t.GetBrackets(e),c=t.GetArgument(e);if("\\"===r.charAt(0)&&(r=r.substr(1)),!r.match(/^(.|[a-z]+)$/i))throw new n.default("IllegalControlSequenceName","Illegal control sequence name for %1",e);if(o&&!(o=i.default.trimSpaces(o)).match(/^[0-9]+$/))throw new n.default("IllegalParamNumber","Illegal number of parameters specified in %1",e);s.default.addMacro(t,r,l.Macro,[c,o,a])},NewEnvironment:function(t,e){var r=i.default.trimSpaces(t.GetArgument(e)),o=t.GetBrackets(e),a=t.GetBrackets(e),c=t.GetArgument(e),u=t.GetArgument(e);if(o&&!(o=i.default.trimSpaces(o)).match(/^[0-9]+$/))throw new n.default("IllegalParamNumber","Illegal number of parameters specified in %1",e);s.default.addEnvironment(t,r,l.BeginEnv,[!0,c,u,o,a])},MacroDef:function(t,e){var r=s.default.GetCSname(t,e),n=s.default.GetTemplate(t,e,"\\"+r),o=t.GetArgument(e);n instanceof Array?s.default.addMacro(t,r,l.MacroWithTemplate,[o].concat(n)):s.default.addMacro(t,r,l.Macro,[o,n])},Let:function(t,e){var r=s.default.GetCSname(t,e),n=t.GetNext();"="===n&&(t.i++,n=t.GetNext());var a=t.configuration.handlers;if("\\"!==n){t.i++;var i=a.get("delimiter").lookup(n);i?s.default.addDelimiter(t,"\\"+r,i.char,i.attributes):s.default.addMacro(t,r,l.Macro,[n])}else{e=s.default.GetCSname(t,e);var c=a.get("delimiter").lookup("\\"+e);if(c)return void s.default.addDelimiter(t,"\\"+r,c.char,c.attributes);var u=a.get("macro").applicable(e);if(!u)return;if(u instanceof o.MacroMap){var p=u.lookup(e);return void s.default.addMacro(t,r,p.func,p.args,p.symbol)}c=u.lookup(e);var f=s.default.disassembleSymbol(r,c);s.default.addMacro(t,r,(function(t,e){for(var r=[],n=2;nt.configuration.options.maxMacros)throw new n.default("MaxMacroSub1","MathJax maximum macro substitution count exceeded; is here a recursive macro call?")},BeginEnv:function(t,e,r,n,o,a){if(e.getProperty("end")&&t.stack.env.closing===e.getName()){delete t.stack.env.closing;var s=t.string.slice(t.i);return t.string=n,t.i=0,t.Parse(),t.string=s,t.i=0,t.itemFactory.create("end").setProperty("name",e.getName())}if(o){var l=[];if(null!=a){var c=t.GetBrackets("\\begin{"+e.getName()+"}");l.push(null==c?a:c)}for(var u=l.length;u0?[i.toString()].concat(o):i;t.i++}throw new a.default("MissingReplacementString","Missing replacement string for definition of %1",e)},t.GetParameter=function(t,r,n){if(null==n)return t.GetArgument(r);for(var o=t.i,i=0,s=0;t.i=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.NoUndefinedConfiguration=void 0;var o=r(6552);e.NoUndefinedConfiguration=o.Configuration.create("noundefined",{fallback:{macro:function(t,e){var r,o,a=t.create("text","\\"+e),i=t.options.noundefined||{},s={};try{for(var l=n(["color","background","size"]),c=l.next();!c.done;c=l.next()){var u=c.value;i[u]&&(s["math"+u]=i[u])}}catch(t){r={error:t}}finally{try{c&&!c.done&&(o=l.return)&&o.call(l)}finally{if(r)throw r.error}}t.Push(t.create("node","mtext",[],s,a))}},options:{noundefined:{color:"red",background:"",size:""}},priority:3})},9589:function(t,e,r){var n;Object.defineProperty(e,"__esModule",{value:!0}),e.PhysicsConfiguration=void 0;var o=r(6552),a=r(4996);r(8047),e.PhysicsConfiguration=o.Configuration.create("physics",{handler:{macro:["Physics-automatic-bracing-macros","Physics-vector-macros","Physics-vector-chars","Physics-derivative-macros","Physics-expressions-macros","Physics-quick-quad-macros","Physics-bra-ket-macros","Physics-matrix-macros"],character:["Physics-characters"],environment:["Physics-aux-envs"]},items:(n={},n[a.AutoOpen.prototype.kind]=a.AutoOpen,n)})},4996:function(t,e,r){var n,o=this&&this.__extends||(n=function(t,e){return(n=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])})(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}n(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.AutoOpen=void 0;var a=r(7044),i=r(7702),s=r(810),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"kind",{get:function(){return"auto open"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isOpen",{get:function(){return!0},enumerable:!1,configurable:!0}),e.prototype.toMml=function(){var e=this.factory.configuration.parser,r=this.getProperty("right");if(this.getProperty("smash")){var n=t.prototype.toMml.call(this),o=e.create("node","mpadded",[n],{height:0,depth:0});this.Clear(),this.Push(e.create("node","TeXAtom",[o]))}r&&this.Push(new s.default(r,e.stack.env,e.configuration).mml());var a=t.prototype.toMml.call(this);return i.default.fenced(this.factory.configuration,this.getProperty("open"),a,this.getProperty("close"),this.getProperty("big"))},e.prototype.checkItem=function(e){var r=e.getProperty("autoclose");return r&&r===this.getProperty("close")?this.getProperty("ignore")?(this.Clear(),[[],!0]):[[this.toMml()],!0]:t.prototype.checkItem.call(this,e)},e}(a.BaseItem);e.AutoOpen=l},8047:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0});var n=r(7628),o=r(1541),a=r(7007),i=r(4708),s=r(8921);new n.CommandMap("Physics-automatic-bracing-macros",{quantity:"Quantity",qty:"Quantity",pqty:["Quantity","(",")",!0],bqty:["Quantity","[","]",!0],vqty:["Quantity","|","|",!0],Bqty:["Quantity","{","}",!0],absolutevalue:["Quantity","|","|",!0],abs:["Quantity","|","|",!0],norm:["Quantity","\\|","\\|",!0],evaluated:"Eval",eval:"Eval",order:["Quantity","(",")",!0,"O",a.TexConstant.Variant.CALLIGRAPHIC],commutator:"Commutator",comm:"Commutator",anticommutator:["Commutator","\\{","\\}"],acomm:["Commutator","\\{","\\}"],poissonbracket:["Commutator","\\{","\\}"],pb:["Commutator","\\{","\\}"]},o.default),new n.CharacterMap("Physics-vector-chars",i.default.mathchar0mi,{dotproduct:["\u22c5",{mathvariant:a.TexConstant.Variant.BOLD}],vdot:["\u22c5",{mathvariant:a.TexConstant.Variant.BOLD}],crossproduct:"\xd7",cross:"\xd7",cp:"\xd7",gradientnabla:["\u2207",{mathvariant:a.TexConstant.Variant.BOLD}],real:["\u211c",{mathvariant:a.TexConstant.Variant.NORMAL}],imaginary:["\u2111",{mathvariant:a.TexConstant.Variant.NORMAL}]}),new n.CommandMap("Physics-vector-macros",{vectorbold:"VectorBold",vb:"VectorBold",vectorarrow:["StarMacro",1,"\\vec{\\vb","{#1}}"],va:["StarMacro",1,"\\vec{\\vb","{#1}}"],vectorunit:["StarMacro",1,"\\hat{\\vb","{#1}}"],vu:["StarMacro",1,"\\hat{\\vb","{#1}}"],gradient:["OperatorApplication","\\gradientnabla","(","["],grad:["OperatorApplication","\\gradientnabla","(","["],divergence:["VectorOperator","\\gradientnabla\\vdot","(","["],div:["VectorOperator","\\gradientnabla\\vdot","(","["],curl:["VectorOperator","\\gradientnabla\\crossproduct","(","["],laplacian:["OperatorApplication","\\nabla^2","(","["]},o.default),new n.CommandMap("Physics-expressions-macros",{sin:"Expression",sinh:"Expression",arcsin:"Expression",asin:"Expression",cos:"Expression",cosh:"Expression",arccos:"Expression",acos:"Expression",tan:"Expression",tanh:"Expression",arctan:"Expression",atan:"Expression",csc:"Expression",csch:"Expression",arccsc:"Expression",acsc:"Expression",sec:"Expression",sech:"Expression",arcsec:"Expression",asec:"Expression",cot:"Expression",coth:"Expression",arccot:"Expression",acot:"Expression",exp:["Expression",!1],log:"Expression",ln:"Expression",det:["Expression",!1],Pr:["Expression",!1],tr:["Expression",!1],trace:["Expression",!1,"tr"],Tr:["Expression",!1],Trace:["Expression",!1,"Tr"],rank:"NamedFn",erf:["Expression",!1],Res:["OperatorApplication","{\\rm Res}","(","[","{"],principalvalue:["OperatorApplication","{\\cal P}"],pv:["OperatorApplication","{\\cal P}"],PV:["OperatorApplication","{\\rm P.V.}"],Re:["OperatorApplication","{\\rm Re}","{"],Im:["OperatorApplication","{\\rm Im}","{"],sine:["NamedFn","sin"],hypsine:["NamedFn","sinh"],arcsine:["NamedFn","arcsin"],asine:["NamedFn","asin"],cosine:["NamedFn","cos"],hypcosine:["NamedFn","cosh"],arccosine:["NamedFn","arccos"],acosine:["NamedFn","acos"],tangent:["NamedFn","tan"],hyptangent:["NamedFn","tanh"],arctangent:["NamedFn","arctan"],atangent:["NamedFn","atan"],cosecant:["NamedFn","csc"],hypcosecant:["NamedFn","csch"],arccosecant:["NamedFn","arccsc"],acosecant:["NamedFn","acsc"],secant:["NamedFn","sec"],hypsecant:["NamedFn","sech"],arcsecant:["NamedFn","arcsec"],asecant:["NamedFn","asec"],cotangent:["NamedFn","cot"],hypcotangent:["NamedFn","coth"],arccotangent:["NamedFn","arccot"],acotangent:["NamedFn","acot"],exponential:["NamedFn","exp"],logarithm:["NamedFn","log"],naturallogarithm:["NamedFn","ln"],determinant:["NamedFn","det"],Probability:["NamedFn","Pr"]},o.default),new n.CommandMap("Physics-quick-quad-macros",{qqtext:"Qqtext",qq:"Qqtext",qcomma:["Macro","\\qqtext*{,}"],qc:["Macro","\\qqtext*{,}"],qcc:["Qqtext","c.c."],qif:["Qqtext","if"],qthen:["Qqtext","then"],qelse:["Qqtext","else"],qotherwise:["Qqtext","otherwise"],qunless:["Qqtext","unless"],qgiven:["Qqtext","given"],qusing:["Qqtext","using"],qassume:["Qqtext","assume"],"qsince,":["Qqtext","since,"],qlet:["Qqtext","let"],qfor:["Qqtext","for"],qall:["Qqtext","all"],qeven:["Qqtext","even"],qodd:["Qqtext","odd"],qinteger:["Qqtext","integer"],qand:["Qqtext","and"],qor:["Qqtext","or"],qas:["Qqtext","as"],qin:["Qqtext","in"]},o.default),new n.CommandMap("Physics-derivative-macros",{flatfrac:["Macro","\\left.#1\\middle/#2\\right.",2],differential:["Differential","{\\rm d}"],dd:["Differential","{\\rm d}"],variation:["Differential","\\delta"],var:["Differential","\\delta"],derivative:["Derivative",2,"{\\rm d}"],dv:["Derivative",2,"{\\rm d}"],partialderivative:["Derivative",3,"\\partial"],pderivative:["Derivative",3,"\\partial"],pdv:["Derivative",3,"\\partial"],functionalderivative:["Derivative",2,"\\delta"],fderivative:["Derivative",2,"\\delta"],fdv:["Derivative",2,"\\delta"]},o.default),new n.CommandMap("Physics-bra-ket-macros",{bra:"Bra",ket:"Ket",innerproduct:"BraKet",braket:"BraKet",outerproduct:"KetBra",dyad:"KetBra",ketbra:"KetBra",op:"KetBra",expectationvalue:"Expectation",expval:"Expectation",ev:"Expectation",matrixelement:"MatrixElement",matrixel:"MatrixElement",mel:"MatrixElement"},o.default),new n.CommandMap("Physics-matrix-macros",{matrixquantity:"MatrixQuantity",mqty:"MatrixQuantity",pmqty:["Macro","\\mqty(#1)",1],Pmqty:["Macro","\\mqty*(#1)",1],bmqty:["Macro","\\mqty[#1]",1],vmqty:["Macro","\\mqty|#1|",1],smallmatrixquantity:["MatrixQuantity",!0],smqty:["MatrixQuantity",!0],spmqty:["Macro","\\smqty(#1)",1],sPmqty:["Macro","\\smqty*(#1)",1],sbmqty:["Macro","\\smqty[#1]",1],svmqty:["Macro","\\smqty|#1|",1],matrixdeterminant:["Macro","\\vmqty{#1}",1],mdet:["Macro","\\vmqty{#1}",1],smdet:["Macro","\\svmqty{#1}",1],identitymatrix:"IdentityMatrix",imat:"IdentityMatrix",xmatrix:"XMatrix",xmat:"XMatrix",zeromatrix:["Macro","\\xmat{0}{#1}{#2}",2],zmat:["Macro","\\xmat{0}{#1}{#2}",2],paulimatrix:"PauliMatrix",pmat:"PauliMatrix",diagonalmatrix:"DiagonalMatrix",dmat:"DiagonalMatrix",antidiagonalmatrix:["DiagonalMatrix",!0],admat:["DiagonalMatrix",!0]},o.default),new n.EnvironmentMap("Physics-aux-envs",i.default.environment,{smallmatrix:["Array",null,null,null,"c","0.333em",".2em","S",1]},o.default),new n.MacroMap("Physics-characters",{"|":["AutoClose",s.TEXCLASS.ORD],")":"AutoClose","]":"AutoClose"},o.default)},1541:function(t,e,r){var n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i};Object.defineProperty(e,"__esModule",{value:!0});var o=r(724),a=r(810),i=r(3466),s=r(8921),l=r(7702),c=r(8321),u=r(8644),p={},f={"(":")","[":"]","{":"}","|":"|"},d=/^(b|B)i(g{1,2})$/;p.Quantity=function(t,e,r,n,o,u,p){void 0===r&&(r="("),void 0===n&&(n=")"),void 0===o&&(o=!1),void 0===u&&(u=""),void 0===p&&(p="");var h=!!o&&t.GetStar(),m=t.GetNext(),g=t.i,y=null;if("\\"===m){if(t.i++,!(y=t.GetCS()).match(d)){var v=t.create("node","mrow");return t.Push(l.default.fenced(t.configuration,r,v,n)),void(t.i=g)}m=t.GetNext()}var b=f[m];if(o&&"{"!==m)throw new i.default("MissingArgFor","Missing argument for %1",t.currentCS);if(!b){v=t.create("node","mrow");return t.Push(l.default.fenced(t.configuration,r,v,n)),void(t.i=g)}if(u){var x=t.create("token","mi",{texClass:s.TEXCLASS.OP},u);p&&c.default.setAttribute(x,"mathvariant",p),t.Push(t.itemFactory.create("fn",x))}if("{"===m){var _=t.GetArgument(e);return m=o?r:"\\{",b=o?n:"\\}",_=h?m+" "+_+" "+b:y?"\\"+y+"l"+m+" "+_+" \\"+y+"r"+b:"\\left"+m+" "+_+" \\right"+b,void t.Push(new a.default(_,t.stack.env,t.configuration).mml())}o&&(m=r,b=n),t.i++,t.Push(t.itemFactory.create("auto open").setProperties({open:m,close:b,big:y}))},p.Eval=function(t,e){var r=t.GetStar(),n=t.GetNext();if("{"!==n){if("("===n||"["===n)return t.i++,void t.Push(t.itemFactory.create("auto open").setProperties({open:n,close:"|",smash:r,right:"\\vphantom{\\int}"}));throw new i.default("MissingArgFor","Missing argument for %1",t.currentCS)}var o=t.GetArgument(e),a="\\left. "+(r?"\\smash{"+o+"}":o)+" \\vphantom{\\int}\\right|";t.string=t.string.slice(0,t.i)+a+t.string.slice(t.i)},p.Commutator=function(t,e,r,n){void 0===r&&(r="["),void 0===n&&(n="]");var o=t.GetStar(),s=t.GetNext(),l=null;if("\\"===s){if(t.i++,!(l=t.GetCS()).match(d))throw new i.default("MissingArgFor","Missing argument for %1",t.currentCS);s=t.GetNext()}if("{"!==s)throw new i.default("MissingArgFor","Missing argument for %1",t.currentCS);var c=t.GetArgument(e)+","+t.GetArgument(e);c=o?r+" "+c+" "+n:l?"\\"+l+"l"+r+" "+c+" \\"+l+"r"+n:"\\left"+r+" "+c+" \\right"+n,t.Push(new a.default(c,t.stack.env,t.configuration).mml())};var h=[65,90],m=[97,122],g=[913,937],y=[945,969],v=[48,57];function b(t,e){return t>=e[0]&&t<=e[1]}function x(t,e,r,n){var o=t.configuration.parser,a=u.NodeFactory.createToken(t,e,r,n),i=n.codePointAt(0);return 1===n.length&&!o.stack.env.font&&o.stack.env.vectorFont&&(b(i,h)||b(i,m)||b(i,g)||b(i,v)||b(i,y)&&o.stack.env.vectorStar||c.default.getAttribute(a,"accent"))&&c.default.setAttribute(a,"mathvariant",o.stack.env.vectorFont),a}p.VectorBold=function(t,e){var r=t.GetStar(),n=t.GetArgument(e),o=t.configuration.nodeFactory.get("token"),i=t.stack.env.font;delete t.stack.env.font,t.configuration.nodeFactory.set("token",x),t.stack.env.vectorFont=r?"bold-italic":"bold",t.stack.env.vectorStar=r;var s=new a.default(n,t.stack.env,t.configuration).mml();i&&(t.stack.env.font=i),delete t.stack.env.vectorFont,delete t.stack.env.vectorStar,t.configuration.nodeFactory.set("token",o),t.Push(s)},p.StarMacro=function(t,e,r){for(var n=[],o=3;ot.configuration.options.maxMacros)throw new i.default("MaxMacroSub1","MathJax maximum macro substitution count exceeded; is there a recursive macro call?")};var _=function(t,e,r,n,o){var i=new a.default(n,t.stack.env,t.configuration).mml();t.Push(t.itemFactory.create(e,i));var s=t.GetNext(),l=f[s];if(l){var c=-1!==o.indexOf(s);if("{"===s){var u=(c?"\\left\\{":"")+" "+t.GetArgument(r)+" "+(c?"\\right\\}":"");return t.string=u+t.string.slice(t.i),void(t.i=0)}c&&(t.i++,t.Push(t.itemFactory.create("auto open").setProperties({open:s,close:l})))}};function A(t,e,r){var o=n(t,3),a=o[0],i=o[1],s=o[2];return e&&r?"\\left\\langle{"+a+"}\\middle\\vert{"+i+"}\\middle\\vert{"+s+"}\\right\\rangle":e?"\\langle{"+a+"}\\vert{"+i+"}\\vert{"+s+"}\\rangle":"\\left\\langle{"+a+"}\\right\\vert{"+i+"}\\left\\vert{"+s+"}\\right\\rangle"}p.OperatorApplication=function(t,e,r){for(var n=[],o=3;o2&&l.length>2?(u="^{"+(l.length-1)+"}",c=!0):null!=i&&(r>2&&l.length>1&&(c=!0),p=u="^{"+i+"}");for(var f=o?"\\flatfrac":"\\frac",d=l.length>1?l[0]:"",h=l.length>1?l[1]:l[0],m="",g=2,y=void 0;y=l[g];g++)m+=n+" "+y;var v=f+"{"+n+u+d+"}{"+n+" "+h+p+" "+m+"}";t.Push(new a.default(v,t.stack.env,t.configuration).mml()),"("===t.GetNext()&&(t.i++,t.Push(t.itemFactory.create("auto open").setProperties({open:"(",close:")",ignore:c})))},p.Bra=function(t,e){var r=t.GetStar(),n=t.GetArgument(e),o="",i=!1,s=!1;if("\\"===t.GetNext()){var l=t.i;t.i++;var c=t.GetCS(),u=t.lookup("macro",c);u&&"ket"===u.symbol?(i=!0,l=t.i,s=t.GetStar(),"{"===t.GetNext()?o=t.GetArgument(c,!0):(t.i=l,s=!1)):t.i=l}var p="";p=i?r||s?"\\langle{"+n+"}\\vert{"+o+"}\\rangle":"\\left\\langle{"+n+"}\\middle\\vert{"+o+"}\\right\\rangle":r||s?"\\langle{"+n+"}\\vert":"\\left\\langle{"+n+"}\\right\\vert{"+o+"}",t.Push(new a.default(p,t.stack.env,t.configuration).mml())},p.Ket=function(t,e){var r=t.GetStar(),n=t.GetArgument(e),o=r?"\\vert{"+n+"}\\rangle":"\\left\\vert{"+n+"}\\right\\rangle";t.Push(new a.default(o,t.stack.env,t.configuration).mml())},p.BraKet=function(t,e){var r=t.GetStar(),n=t.GetArgument(e),o=null;"{"===t.GetNext()&&(o=t.GetArgument(e,!0));var i="";i=null==o?r?"\\langle{"+n+"}\\vert{"+n+"}\\rangle":"\\left\\langle{"+n+"}\\middle\\vert{"+n+"}\\right\\rangle":r?"\\langle{"+n+"}\\vert{"+o+"}\\rangle":"\\left\\langle{"+n+"}\\middle\\vert{"+o+"}\\right\\rangle",t.Push(new a.default(i,t.stack.env,t.configuration).mml())},p.KetBra=function(t,e){var r=t.GetStar(),n=t.GetArgument(e),o=null;"{"===t.GetNext()&&(o=t.GetArgument(e,!0));var i="";i=null==o?r?"\\vert{"+n+"}\\rangle\\!\\langle{"+n+"}\\vert":"\\left\\vert{"+n+"}\\middle\\rangle\\!\\middle\\langle{"+n+"}\\right\\vert":r?"\\vert{"+n+"}\\rangle\\!\\langle{"+o+"}\\vert":"\\left\\vert{"+n+"}\\middle\\rangle\\!\\middle\\langle{"+o+"}\\right\\vert",t.Push(new a.default(i,t.stack.env,t.configuration).mml())},p.Expectation=function(t,e){var r=t.GetStar(),n=r&&t.GetStar(),o=t.GetArgument(e),i=null;"{"===t.GetNext()&&(i=t.GetArgument(e,!0));var s=o&&i?A([i,o,i],r,n):r?"\\langle {"+o+"} \\rangle":"\\left\\langle {"+o+"} \\right\\rangle";t.Push(new a.default(s,t.stack.env,t.configuration).mml())},p.MatrixElement=function(t,e){var r=t.GetStar(),n=r&&t.GetStar(),o=A([t.GetArgument(e),t.GetArgument(e),t.GetArgument(e)],r,n);t.Push(new a.default(o,t.stack.env,t.configuration).mml())},p.MatrixQuantity=function(t,e,r){var n=t.GetStar(),o=r?"smallmatrix":"array",i="",s="",l="";switch(t.GetNext()){case"{":i=t.GetArgument(e);break;case"(":t.i++,s=n?"\\lgroup":"(",l=n?"\\rgroup":")",i=t.GetUpTo(e,")");break;case"[":t.i++,s="[",l="]",i=t.GetUpTo(e,"]");break;case"|":t.i++,s="|",l="|",i=t.GetUpTo(e,"|");break;default:s="(",l=")"}var c=(s?"\\left":"")+s+"\\begin{"+o+"}{} "+i+"\\end{"+o+"}"+(s?"\\right":"")+l;t.Push(new a.default(c,t.stack.env,t.configuration).mml())},p.IdentityMatrix=function(t,e){var r=t.GetArgument(e),n=parseInt(r,10);if(isNaN(n))throw new i.default("InvalidNumber","Invalid number");if(n<=1)return t.string="1"+t.string.slice(t.i),void(t.i=0);for(var o=Array(n).fill("0"),a=[],s=0;s=o){a.push(t.string.slice(s,o));break}s=t.i,a.push(i)}t.string=function(t,e){for(var r=t.length,n=[],o=0;o=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},a=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r":["Spacer",i.MATHSPACE.mediummathspace],";":["Spacer",i.MATHSPACE.thickmathspace],"!":["Spacer",i.MATHSPACE.negativethinmathspace],enspace:["Spacer",.5],quad:["Spacer",1],qquad:["Spacer",2],thinspace:["Spacer",i.MATHSPACE.thinmathspace],negthinspace:["Spacer",i.MATHSPACE.negativethinmathspace],hskip:"Hskip",hspace:"Hskip",kern:"Hskip",mskip:"Hskip",mspace:"Hskip",mkern:"Hskip",rule:"rule",Rule:["Rule"],Space:["Rule","blank"],color:"CheckAutoload",textcolor:"CheckAutoload",colorbox:"CheckAutoload",fcolorbox:"CheckAutoload",href:"CheckAutoload",style:"CheckAutoload",class:"CheckAutoload",cssId:"CheckAutoload",unicode:"CheckAutoload",ref:["HandleRef",!1],eqref:["HandleRef",!0]},a.TextMacrosMethods)},440:function(t,e,r){Object.defineProperty(e,"__esModule",{value:!0}),e.TextMacrosMethods=void 0;var n=r(810),o=r(239),a=r(724);e.TextMacrosMethods={Comment:function(t,e){for(;t.i=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var n,o,a=r.call(t),i=[];try{for(;(void 0===e||e-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(t){o={error:t}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},s=this&&this.__spreadArray||function(t,e){for(var r=0,n=e.length,o=t.length;r=0&&(l[c]=r),n&&s[e]&&((0,t.combineConfig)(s,(o={},a=r,i=s[e],a in o?Object.defineProperty(o,a,{value:i,enumerable:!0,configurable:!0,writable:!0}):o[a]=i,o)),delete s[e])}}function vt(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};function o(e){return"object"==typeof e&&null!==e}function a(e,t){var r,i;try{for(var c=n(Object.keys(t)),s=c.next();!s.done;s=c.next()){var u=s.value;"__esModule"!==u&&(!o(e[u])||!o(t[u])||t[u]instanceof Promise?null!==t[u]&&void 0!==t[u]&&(e[u]=t[u]):a(e[u],t[u]))}}catch(e){r={error:e}}finally{try{s&&!s.done&&(i=c.return)&&i.call(c)}finally{if(r)throw r.error}}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.MathJax=t.combineWithMathJax=t.combineDefaults=t.combineConfig=t.isObject=void 0,t.isObject=o,t.combineConfig=a,t.combineDefaults=function e(t,r,a){var i,c;t[r]||(t[r]={}),t=t[r];try{for(var s=n(Object.keys(a)),u=s.next();!u.done;u=s.next()){var l=u.value;o(t[l])&&o(a[l])?e(t,l,a[l]):null==t[l]&&null!=a[l]&&(t[l]=a[l])}}catch(e){i={error:e}}finally{try{u&&!u.done&&(c=s.return)&&c.call(s)}finally{if(i)throw i.error}}return t},t.combineWithMathJax=function(e){return a(t.MathJax,e)},void 0===r.g.MathJax&&(r.g.MathJax={}),r.g.MathJax.version||(r.g.MathJax={version:"3.1.4",_:{},config:r.g.MathJax}),t.MathJax=r.g.MathJax},235:function(e,t,r){var n=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(t,"__esModule",{value:!0}),t.CONFIG=t.MathJax=t.Loader=t.PathFilters=t.PackageError=t.Package=void 0;var o=r(515),a=r(265),i=r(265);Object.defineProperty(t,"Package",{enumerable:!0,get:function(){return i.Package}}),Object.defineProperty(t,"PackageError",{enumerable:!0,get:function(){return i.PackageError}});var c,s=r(525);t.PathFilters={source:function(e){return t.CONFIG.source.hasOwnProperty(e.name)&&(e.name=t.CONFIG.source[e.name]),!0},normalize:function(e){var t=e.name;return t.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i)||(e.name="[mathjax]/"+t.replace(/^\.\//,"")),e.addExtension&&!t.match(/\.[^\/]+$/)&&(e.name+=".js"),!0},prefix:function(e){for(var r;(r=e.name.match(/^\[([^\]]*)\]/))&&t.CONFIG.paths.hasOwnProperty(r[1]);)e.name=t.CONFIG.paths[r[1]]+e.name.substr(r[0].length);return!0}},function(e){e.ready=function(){for(var e,t,r=[],o=0;o=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},c=this&&this.__spreadArray||function(e,t){for(var r=0,n=t.length,o=e.length;r=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},c=this&&this.__spreadArray||function(e,t){for(var r=0,n=t.length,o=e.length;rt.length}}}},e.prototype.add=function(t,r){void 0===r&&(r=e.DEFAULTPRIORITY);var n=this.items.length;do{n--}while(n>=0&&r=0&&this.items[t].item!==e);t>=0&&this.items.splice(t,1)},e.prototype.toArray=function(){return Array.from(this)},e.DEFAULTPRIORITY=5,e}();t.PrioritizedList=r}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n].call(a.exports,a,a.exports,r),a.exports}r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),function(){var e=r(515),t=r(235),n=r(265);(0,e.combineWithMathJax)({_:{components:{loader:t,package:n}}});var o,a={tex:"[mathjax]/input/tex/extensions",sre:"[mathjax]/sre/"+("undefined"==typeof window?"sre-node":"sre_browser")},i=["[tex]/action","[tex]/ams","[tex]/amscd","[tex]/bbox","[tex]/boldsymbol","[tex]/braket","[tex]/bussproofs","[tex]/cancel","[tex]/color","[tex]/configmacros","[tex]/enclose","[tex]/extpfeil","[tex]/html","[tex]/mhchem","[tex]/newcommand","[tex]/noerrors","[tex]/noundefined","[tex]/physics","[tex]/require","[tex]/tagformat","[tex]/textmacros","[tex]/unicode","[tex]/verb"],c={startup:["loader"],"input/tex":["input/tex-base","[tex]/ams","[tex]/newcommand","[tex]/noundefined","[tex]/require","[tex]/autoload","[tex]/configmacros"],"input/tex-full":["input/tex-base","[tex]/all-packages"].concat(i),"[tex]/all-packages":i};function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTML=void 0;var s=r(716),l=r(4477),h=r(4142),c=r(6914),u=r(6720),p=function(t){function e(e){void 0===e&&(e=null);var r=t.call(this,e,l.CHTMLWrapperFactory,h.TeXFont)||this;return r.chtmlStyles=null,r.font.adaptiveCSS(r.options.adaptiveCSS),r}return n(e,t),e.prototype.escaped=function(t,e){return this.setDocument(e),this.html("span",{},[this.text(t.math)])},e.prototype.styleSheet=function(r){if(this.chtmlStyles&&!this.options.adaptiveCSS)return this.chtmlStyles;var o=this.chtmlStyles=t.prototype.styleSheet.call(this,r);return this.adaptor.setAttribute(o,"id",e.STYLESHEETID),o},e.prototype.addClassStyles=function(e){var r;this.options.adaptiveCSS&&!e.used||(e.autoStyle&&"unknown"!==e.kind&&this.cssStyles.addStyles(((r={})["mjx-"+e.kind]={display:"inline-block","text-align":"left"},r)),t.prototype.addClassStyles.call(this,e))},e.prototype.processMath=function(t,e){this.factory.wrap(t).toCHTML(e)},e.prototype.clearCache=function(){var t,e;this.cssStyles.clear(),this.font.clearCache();try{for(var r=a(this.factory.getKinds()),o=r.next();!o.done;o=r.next()){var n=o.value;this.factory.getNodeClass(n).used=!1}}catch(e){t={error:e}}finally{try{o&&!o.done&&(e=r.return)&&e.call(r)}finally{if(t)throw t.error}}},e.prototype.reset=function(){this.clearCache()},e.prototype.unknownText=function(t,e){var r={},o=100/this.math.metrics.scale;if(100!==o&&(r["font-size"]=this.fixed(o,1)+"%",r.padding=c.em(75/o)+" 0 "+c.em(20/o)+" 0"),"-explicitFont"!==e){var n=u.unicodeChars(t);(1!==n.length||n[0]<119808||n[0]>120831)&&this.cssFontStyles(this.font.getCssFont(e),r)}return this.html("mjx-utext",{variant:e,style:r},[this.text(t)])},e.prototype.measureTextNode=function(t){var e=this.adaptor;t=e.clone(t);var r=this.html("mjx-measure-text",{style:{position:"absolute","white-space":"nowrap"}},[t]);e.append(e.parent(this.math.start.node),this.container),e.append(this.container,r);var o=e.nodeSize(t,this.math.metrics.em)[0]/this.math.metrics.scale;return e.remove(this.container),e.remove(r),{w:o,h:.75,d:.2}},e.NAME="CHTML",e.OPTIONS=i(i({},s.CommonOutputJax.OPTIONS),{adaptiveCSS:!0}),e.commonStyles={'mjx-container[jax="CHTML"]':{"line-height":0},'mjx-container [space="1"]':{"margin-left":".111em"},'mjx-container [space="2"]':{"margin-left":".167em"},'mjx-container [space="3"]':{"margin-left":".222em"},'mjx-container [space="4"]':{"margin-left":".278em"},'mjx-container [space="5"]':{"margin-left":".333em"},'mjx-container [rspace="1"]':{"margin-right":".111em"},'mjx-container [rspace="2"]':{"margin-right":".167em"},'mjx-container [rspace="3"]':{"margin-right":".222em"},'mjx-container [rspace="4"]':{"margin-right":".278em"},'mjx-container [rspace="5"]':{"margin-right":".333em"},'mjx-container [size="s"]':{"font-size":"70.7%"},'mjx-container [size="ss"]':{"font-size":"50%"},'mjx-container [size="Tn"]':{"font-size":"60%"},'mjx-container [size="sm"]':{"font-size":"85%"},'mjx-container [size="lg"]':{"font-size":"120%"},'mjx-container [size="Lg"]':{"font-size":"144%"},'mjx-container [size="LG"]':{"font-size":"173%"},'mjx-container [size="hg"]':{"font-size":"207%"},'mjx-container [size="HG"]':{"font-size":"249%"},'mjx-container [width="full"]':{width:"100%"},"mjx-box":{display:"inline-block"},"mjx-block":{display:"block"},"mjx-itable":{display:"inline-table"},"mjx-row":{display:"table-row"},"mjx-row > *":{display:"table-cell"},"mjx-mtext":{display:"inline-block"},"mjx-mstyle":{display:"inline-block"},"mjx-merror":{display:"inline-block",color:"red","background-color":"yellow"},"mjx-mphantom":{visibility:"hidden"}},e.STYLESHEETID="MJX-CHTML-styles",e}(s.CommonOutputJax);e.CHTML=p},2098:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,o=arguments.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},h=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.AddCSS=e.CHTMLFontData=void 0;var c=r(9250),u=r(6914);s(r(9250),e);var p=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.charOptions=function(e,r){return t.charOptions.call(this,e,r)},e.prototype.adaptiveCSS=function(t){this.options.adaptiveCSS=t},e.prototype.clearCache=function(){var t,e,r,o,n,i;if(this.options.adaptiveCSS){try{for(var a=l(Object.keys(this.delimiters)),s=a.next();!s.done;s=a.next()){var h=s.value;this.delimiters[parseInt(h)].used=!1}}catch(e){t={error:e}}finally{try{s&&!s.done&&(e=a.return)&&e.call(a)}finally{if(t)throw t.error}}try{for(var c=l(Object.keys(this.variant)),u=c.next();!u.done;u=c.next()){var p=u.value,d=this.variant[p].chars;try{for(var f=(n=void 0,l(Object.keys(d))),m=f.next();!m.done;m=f.next()){h=m.value;var y=d[parseInt(h)][3];y&&(y.used=!1)}}catch(t){n={error:t}}finally{try{m&&!m.done&&(i=f.return)&&i.call(f)}finally{if(n)throw n.error}}}}catch(t){r={error:t}}finally{try{u&&!u.done&&(o=c.return)&&o.call(c)}finally{if(r)throw r.error}}}},e.prototype.createVariant=function(e,r,o){void 0===r&&(r=null),void 0===o&&(o=null),t.prototype.createVariant.call(this,e,r,o);var n=this.constructor;this.variant[e].classes=n.defaultVariantClasses[e],this.variant[e].letter=n.defaultVariantLetters[e]},e.prototype.defineChars=function(r,o){var n,i;t.prototype.defineChars.call(this,r,o);var a=this.variant[r].letter;try{for(var s=l(Object.keys(o)),h=s.next();!h.done;h=s.next()){var c=h.value,u=e.charOptions(o,parseInt(c));void 0===u.f&&(u.f=a)}}catch(t){n={error:t}}finally{try{h&&!h.done&&(i=s.return)&&i.call(s)}finally{if(n)throw n.error}}},Object.defineProperty(e.prototype,"styles",{get:function(){var t,e,r=this.constructor,o=i({},r.defaultStyles);this.addFontURLs(o,r.defaultFonts,this.options.fontURL);try{for(var n=l(Object.keys(this.delimiters)),a=n.next();!a.done;a=n.next()){var s=a.value,h=parseInt(s);this.addDelimiterStyles(o,h,this.delimiters[h])}}catch(e){t={error:e}}finally{try{a&&!a.done&&(e=n.return)&&e.call(n)}finally{if(t)throw t.error}}return this.addVariantChars(o),o},enumerable:!1,configurable:!0}),e.prototype.addVariantChars=function(t){var e,r,o,n,i=!this.options.adaptiveCSS;try{for(var a=l(Object.keys(this.variant)),s=a.next();!s.done;s=a.next()){var h=s.value,c=this.variant[h],u=c.letter;try{for(var p=(o=void 0,l(Object.keys(c.chars))),d=p.next();!d.done;d=p.next()){var f=d.value,m=parseInt(f),y=c.chars[m];(y[3]||{}).smp||(i&&y.length<4&&(y[3]={}),(4===y.length||i)&&this.addCharStyles(t,u,m,y))}}catch(t){o={error:t}}finally{try{d&&!d.done&&(n=p.return)&&n.call(p)}finally{if(o)throw o.error}}}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=a.return)&&r.call(a)}finally{if(e)throw e.error}}},e.prototype.addFontURLs=function(t,e,r){var o,n;try{for(var a=l(Object.keys(e)),s=a.next();!s.done;s=a.next()){var h=s.value,c=i({},e[h]);c.src=c.src.replace(/%%URL%%/,r),t[h]=c}}catch(t){o={error:t}}finally{try{s&&!s.done&&(n=a.return)&&n.call(a)}finally{if(o)throw o.error}}},e.prototype.addDelimiterStyles=function(t,e,r){if(!this.options.adaptiveCSS||r.used){var o=this.charSelector(e);r.c&&r.c!==e&&(t[".mjx-stretched mjx-c"+o+"::before"]={content:this.charContent(r.c)}),r.stretch&&(1===r.dir?this.addDelimiterVStyles(t,o,r):this.addDelimiterHStyles(t,o,r))}},e.prototype.addDelimiterVStyles=function(t,e,r){var o=r.HDW,n=h(r.stretch,4),i=n[0],a=n[1],s=n[2],l=n[3],c=this.addDelimiterVPart(t,e,"beg",i,o);this.addDelimiterVPart(t,e,"ext",a,o);var u=this.addDelimiterVPart(t,e,"end",s,o),p={};if(l){var d=this.addDelimiterVPart(t,e,"mid",l,o);p.height="50%",t["mjx-stretchy-v"+e+" > mjx-mid"]={"margin-top":this.em(-d/2),"margin-bottom":this.em(-d/2)}}c&&(p["border-top-width"]=this.em0(c-.03)),u&&(p["border-bottom-width"]=this.em0(u-.03),t["mjx-stretchy-v"+e+" > mjx-end"]={"margin-top":this.em(-u)}),Object.keys(p).length&&(t["mjx-stretchy-v"+e+" > mjx-ext"]=p)},e.prototype.addDelimiterVPart=function(t,e,r,o,n){if(!o)return 0;var i=this.getDelimiterData(o),a=(n[2]-i[2])/2,s={content:this.charContent(o)};return"ext"!==r?s.padding=this.padding(i,a):(s.width=this.em0(n[2]),a&&(s["padding-left"]=this.em0(a))),t["mjx-stretchy-v"+e+" mjx-"+r+" mjx-c::before"]=s,i[0]+i[1]},e.prototype.addDelimiterHStyles=function(t,e,r){var o=h(r.stretch,4),n=o[0],i=o[1],a=o[2],s=o[3],l=r.HDW;this.addDelimiterHPart(t,e,"beg",n,l),this.addDelimiterHPart(t,e,"ext",i,l),this.addDelimiterHPart(t,e,"end",a,l),s&&(this.addDelimiterHPart(t,e,"mid",s,l),t["mjx-stretchy-h"+e+" > mjx-ext"]={width:"50%"})},e.prototype.addDelimiterHPart=function(t,e,r,o,n){if(o){var i=this.getDelimiterData(o)[3],a={content:i&&i.c?'"'+i.c+'"':this.charContent(o)};a.padding=this.padding(n,0,-n[2]),t["mjx-stretchy-h"+e+" mjx-"+r+" mjx-c::before"]=a}},e.prototype.addCharStyles=function(t,e,r,o){var n=o[3];if(!this.options.adaptiveCSS||n.used){var i=void 0!==n.f?n.f:e;t["mjx-c"+this.charSelector(r)+(i?".TEX-"+i:"")+"::before"]={padding:this.padding(o,0,n.ic||0),content:null!=n.c?'"'+n.c+'"':this.charContent(r)}}},e.prototype.getDelimiterData=function(t){return this.getChar("-smallop",t)},e.prototype.em=function(t){return u.em(t)},e.prototype.em0=function(t){return u.em(Math.max(0,t))},e.prototype.padding=function(t,e,r){var o=h(t,3),n=o[0],i=o[1];return void 0===e&&(e=0),void 0===r&&(r=0),[n,o[2]+r,i,e].map(this.em0).join(" ")},e.prototype.charContent=function(t){return'"'+(t>=32&&t<=126&&34!==t&&39!==t&&92!==t?String.fromCharCode(t):"\\"+t.toString(16).toUpperCase())+'"'},e.prototype.charSelector=function(t){return".mjx-c"+t.toString(16).toUpperCase()},e.OPTIONS=i(i({},c.FontData.OPTIONS),{fontURL:"js/output/chtml/fonts/tex-woff-v2"}),e.defaultVariantClasses={},e.defaultVariantLetters={},e.defaultStyles={"mjx-c::before":{display:"block",width:0}},e.defaultFonts={"@font-face /* 0 */":{"font-family":"MJXZERO",src:'url("%%URL%%/MathJax_Zero.woff") format("woff")'}},e}(c.FontData);e.CHTMLFontData=p,e.AddCSS=function(t,e){var r,o;try{for(var n=l(Object.keys(e)),i=n.next();!i.done;i=n.next()){var a=i.value,s=parseInt(a);Object.assign(c.FontData.charOptions(t,s),e[s])}}catch(t){r={error:t}}finally{try{i&&!i.done&&(o=n.return)&&o.call(n)}finally{if(r)throw r.error}}return t}},4458:function(t,e,r){var o=this&&this.__createBinding||(Object.create?function(t,e,r,o){void 0===o&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){void 0===o&&(o=r),t[o]=e[r]}),n=this&&this.__exportStar||function(t,e){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(e,r)||o(e,t,r)},i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.Arrow=e.DiagonalArrow=e.DiagonalStrike=e.Border2=e.Border=e.RenderElement=void 0;var a=r(5373);n(r(5373),e);e.RenderElement=function(t,e){return void 0===e&&(e=""),function(r,o){var n=r.adjustBorder(r.html("mjx-"+t));if(e){var i=r.getOffset(e);if(r.thickness!==a.THICKNESS||i){var s="translate"+e+"("+r.em(r.thickness/2-i)+")";r.adaptor.setStyle(n,"transform",s)}}r.adaptor.append(r.chtml,n)}};e.Border=function(t){return a.CommonBorder((function(e,r){e.adaptor.setStyle(r,"border-"+t,e.em(e.thickness)+" solid")}))(t)};e.Border2=function(t,e,r){return a.CommonBorder2((function(t,o){var n=t.em(t.thickness)+" solid";t.adaptor.setStyle(o,"border-"+e,n),t.adaptor.setStyle(o,"border-"+r,n)}))(t,e,r)};e.DiagonalStrike=function(t,e){return a.CommonDiagonalStrike((function(t){return function(r,o){var n=r.getBBox(),a=n.w,s=n.h,l=n.d,h=i(r.getArgMod(a,s+l),2),c=h[0],u=h[1],p=e*r.thickness/2,d=r.adjustBorder(r.html(t,{style:{width:r.em(u),transform:"rotate("+r.fixed(-e*c)+"rad) translateY("+p+"em)"}}));r.adaptor.append(r.chtml,d)}}))(t)};e.DiagonalArrow=function(t){return a.CommonDiagonalArrow((function(t,e){t.adaptor.append(t.chtml,e)}))(t)};e.Arrow=function(t){return a.CommonArrow((function(t,e){t.adaptor.append(t.chtml,e)}))(t)}},6617:function(t,e,r){var o,n,i=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),a=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLWrapper=e.SPACE=e.FONTSIZE=void 0;var l=r(6914),h=r(1541),c=r(3717);e.FONTSIZE={"70.7%":"s","70%":"s","50%":"ss","60%":"Tn","85%":"sm","120%":"lg","144%":"Lg","173%":"LG","207%":"hg","249%":"HG"},e.SPACE=((n={})[l.em(2/18)]="1",n[l.em(3/18)]="2",n[l.em(4/18)]="3",n[l.em(5/18)]="4",n[l.em(6/18)]="5",n);var u=function(t){function r(){var e=null!==t&&t.apply(this,arguments)||this;return e.chtml=null,e}return i(r,t),r.prototype.toCHTML=function(t){var e,r,o=this.standardCHTMLnode(t);try{for(var n=a(this.childNodes),i=n.next();!i.done;i=n.next()){i.value.toCHTML(o)}}catch(t){e={error:t}}finally{try{i&&!i.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}},r.prototype.standardCHTMLnode=function(t){this.markUsed();var e=this.createCHTMLnode(t);return this.handleStyles(),this.handleVariant(),this.handleScale(),this.handleColor(),this.handleSpace(),this.handleAttributes(),this.handlePWidth(),e},r.prototype.markUsed=function(){this.constructor.used=!0},r.prototype.createCHTMLnode=function(t){var e=this.node.attributes.get("href");return e&&(t=this.adaptor.append(t,this.html("a",{href:e}))),this.chtml=this.adaptor.append(t,this.html("mjx-"+this.node.kind)),this.chtml},r.prototype.handleStyles=function(){if(this.styles){var t=this.styles.cssText;if(t){this.adaptor.setAttribute(this.chtml,"style",t);var e=this.styles.get("font-family");e&&this.adaptor.setStyle(this.chtml,"font-family","MJXZERO, "+e)}}},r.prototype.handleVariant=function(){this.node.isToken&&"-explicitFont"!==this.variant&&this.adaptor.setAttribute(this.chtml,"class",(this.font.getVariant(this.variant)||this.font.getVariant("normal")).classes)},r.prototype.handleScale=function(){this.setScale(this.chtml,this.bbox.rscale)},r.prototype.setScale=function(t,r){var o=Math.abs(r-1)<.001?1:r;if(t&&1!==o){var n=this.percent(o);e.FONTSIZE[n]?this.adaptor.setAttribute(t,"size",e.FONTSIZE[n]):this.adaptor.setStyle(t,"fontSize",n)}return t},r.prototype.handleSpace=function(){var t,r;try{for(var o=a([[this.bbox.L,"space","marginLeft"],[this.bbox.R,"rspace","marginRight"]]),n=o.next();!n.done;n=o.next()){var i=n.value,l=s(i,3),h=l[0],c=l[1],u=l[2];if(h){var p=this.em(h);e.SPACE[p]?this.adaptor.setAttribute(this.chtml,c,e.SPACE[p]):this.adaptor.setStyle(this.chtml,u,p)}}}catch(e){t={error:e}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}},r.prototype.handleColor=function(){var t=this.node.attributes,e=t.getExplicit("mathcolor"),r=t.getExplicit("color"),o=t.getExplicit("mathbackground"),n=t.getExplicit("background");(e||r)&&this.adaptor.setStyle(this.chtml,"color",e||r),(o||n)&&this.adaptor.setStyle(this.chtml,"backgroundColor",o||n)},r.prototype.handleAttributes=function(){var t,e,o,n,i=this.node.attributes,s=i.getAllDefaults(),l=r.skipAttributes;try{for(var h=a(i.getExplicitNames()),c=h.next();!c.done;c=h.next()){var u=c.value;!1!==l[u]&&(u in s||l[u]||this.adaptor.hasAttribute(this.chtml,u))||this.adaptor.setAttribute(this.chtml,u,i.getExplicit(u))}}catch(e){t={error:e}}finally{try{c&&!c.done&&(e=h.return)&&e.call(h)}finally{if(t)throw t.error}}if(i.get("class")){var p=i.get("class").trim().split(/ +/);try{for(var d=a(p),f=d.next();!f.done;f=d.next()){var m=f.value;this.adaptor.addClass(this.chtml,m)}}catch(t){o={error:t}}finally{try{f&&!f.done&&(n=d.return)&&n.call(d)}finally{if(o)throw o.error}}}},r.prototype.handlePWidth=function(){this.bbox.pwidth&&(this.bbox.pwidth===c.BBox.fullWidth?this.adaptor.setAttribute(this.chtml,"width","full"):this.adaptor.setStyle(this.chtml,"width",this.bbox.pwidth))},r.prototype.setIndent=function(t,e,r){var o=this.adaptor;if("center"===e||"left"===e){var n=this.getBBox().L;o.setStyle(t,"margin-left",this.em(r+n))}if("center"===e||"right"===e){var i=this.getBBox().R;o.setStyle(t,"margin-right",this.em(-r+i))}},r.prototype.drawBBox=function(){var t=this.getBBox(),e=t.w,r=t.h,o=t.d,n=t.R,i=this.html("mjx-box",{style:{opacity:.25,"margin-left":this.em(-e-n)}},[this.html("mjx-box",{style:{height:this.em(r),width:this.em(e),"background-color":"red"}}),this.html("mjx-box",{style:{height:this.em(o),width:this.em(e),"margin-left":this.em(-e),"vertical-align":this.em(-o),"background-color":"green"}})]),a=this.chtml||this.parent.chtml,s=this.adaptor.getAttribute(a,"size");s&&this.adaptor.setAttribute(i,"size",s);var l=this.adaptor.getStyle(a,"fontSize");l&&this.adaptor.setStyle(i,"fontSize",l),this.adaptor.append(this.adaptor.parent(a),i),this.adaptor.setStyle(a,"backgroundColor","#FFEE00")},r.prototype.html=function(t,e,r){return void 0===e&&(e={}),void 0===r&&(r=[]),this.jax.html(t,e,r)},r.prototype.text=function(t){return this.jax.text(t)},r.prototype.char=function(t){return this.font.charSelector(t).substr(1)},r.kind="unknown",r.autoStyle=!0,r.used=!1,r}(h.CommonWrapper);e.CHTMLWrapper=u},4477:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLWrapperFactory=void 0;var i=r(1475),a=r(8369),s=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.defaultNodes=a.CHTMLWrappers,e}(i.CommonWrapperFactory);e.CHTMLWrapperFactory=s},8369:function(t,e,r){var o;Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLWrappers=void 0;var n=r(6617),i=r(4155),a=r(3271),s=r(3292),l=r(7013),h=r(9821),c=r(6359),u=r(6024),p=r(7215),d=r(3215),f=r(3126),m=r(7047),y=r(7837),v=r(5437),b=r(7111),x=r(513),g=r(6577),M=r(1096),_=r(6918),w=r(7500),C=r(8709),j=r(7918),S=r(1315),O=r(7795),T=r(518),L=r(1114);e.CHTMLWrappers=((o={})[i.CHTMLmath.kind]=i.CHTMLmath,o[f.CHTMLmrow.kind]=f.CHTMLmrow,o[f.CHTMLinferredMrow.kind]=f.CHTMLinferredMrow,o[a.CHTMLmi.kind]=a.CHTMLmi,o[s.CHTMLmo.kind]=s.CHTMLmo,o[l.CHTMLmn.kind]=l.CHTMLmn,o[h.CHTMLms.kind]=h.CHTMLms,o[c.CHTMLmtext.kind]=c.CHTMLmtext,o[u.CHTMLmspace.kind]=u.CHTMLmspace,o[p.CHTMLmpadded.kind]=p.CHTMLmpadded,o[d.CHTMLmenclose.kind]=d.CHTMLmenclose,o[y.CHTMLmfrac.kind]=y.CHTMLmfrac,o[v.CHTMLmsqrt.kind]=v.CHTMLmsqrt,o[b.CHTMLmroot.kind]=b.CHTMLmroot,o[x.CHTMLmsub.kind]=x.CHTMLmsub,o[x.CHTMLmsup.kind]=x.CHTMLmsup,o[x.CHTMLmsubsup.kind]=x.CHTMLmsubsup,o[g.CHTMLmunder.kind]=g.CHTMLmunder,o[g.CHTMLmover.kind]=g.CHTMLmover,o[g.CHTMLmunderover.kind]=g.CHTMLmunderover,o[M.CHTMLmmultiscripts.kind]=M.CHTMLmmultiscripts,o[m.CHTMLmfenced.kind]=m.CHTMLmfenced,o[_.CHTMLmtable.kind]=_.CHTMLmtable,o[w.CHTMLmtr.kind]=w.CHTMLmtr,o[w.CHTMLmlabeledtr.kind]=w.CHTMLmlabeledtr,o[C.CHTMLmtd.kind]=C.CHTMLmtd,o[j.CHTMLmaction.kind]=j.CHTMLmaction,o[S.CHTMLmglyph.kind]=S.CHTMLmglyph,o[O.CHTMLsemantics.kind]=O.CHTMLsemantics,o[O.CHTMLannotation.kind]=O.CHTMLannotation,o[O.CHTMLannotationXML.kind]=O.CHTMLannotationXML,o[O.CHTMLxml.kind]=O.CHTMLxml,o[T.CHTMLTeXAtom.kind]=T.CHTMLTeXAtom,o[L.CHTMLTextNode.kind]=L.CHTMLTextNode,o[n.CHTMLWrapper.kind]=n.CHTMLWrapper,o)},518:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLTeXAtom=void 0;var i=r(6617),a=r(3438),s=r(4282),l=r(8921),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){if(t.prototype.toCHTML.call(this,e),this.adaptor.setAttribute(this.chtml,"texclass",l.TEXCLASSNAMES[this.node.texClass]),this.node.texClass===l.TEXCLASS.VCENTER){var r=this.childNodes[0].getBBox(),o=r.h,n=(o+r.d)/2+this.font.params.axis_height-o;this.adaptor.setStyle(this.chtml,"verticalAlign",this.em(n))}},e.kind=s.TeXAtom.prototype.kind,e}(a.CommonTeXAtomMixin(i.CHTMLWrapper));e.CHTMLTeXAtom=h},1114:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLTextNode=void 0;var a=r(8921),s=r(6617),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e,r;this.markUsed();var o=this.adaptor,n=this.parent.variant,a=this.node.getText();if("-explicitFont"===n){var s=this.jax.getFontData(this.parent.styles);o.append(t,this.jax.unknownText(a,n,s))}else{var l=this.remappedText(a,n);try{for(var h=i(l),c=h.next();!c.done;c=h.next()){var u=c.value,p=this.getVariantChar(n,u)[3],d=(s=p.f?" TEX-"+p.f:"",p.unknown?this.jax.unknownText(String.fromCodePoint(u),n):this.html("mjx-c",{class:this.char(u)+s}));o.append(t,d),p.used=!0}}catch(t){e={error:t}}finally{try{c&&!c.done&&(r=h.return)&&r.call(h)}finally{if(e)throw e.error}}}},e.kind=a.TextNode.prototype.kind,e.autoStyle=!1,e.styles={"mjx-c":{display:"inline-block"},"mjx-utext":{display:"inline-block",padding:".75em 0 .2em 0"}},e}(r(555).CommonTextNodeMixin(s.CHTMLWrapper));e.CHTMLTextNode=l},7918:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmaction=void 0;var i=r(6617),a=r(3345),s=r(3345),l=r(3969),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e=this.standardCHTMLnode(t);this.selected.toCHTML(e),this.action(this,this.data)},e.prototype.setEventHandler=function(t,e){this.chtml.addEventListener(t,e)},e.kind=l.MmlMaction.prototype.kind,e.styles={"mjx-maction":{position:"relative"},"mjx-maction > mjx-tool":{display:"none",position:"absolute",bottom:0,right:0,width:0,height:0,"z-index":500},"mjx-tool > mjx-tip":{display:"inline-block",padding:".2em",border:"1px solid #888","font-size":"70%","background-color":"#F8F8F8",color:"black","box-shadow":"2px 2px 5px #AAAAAA"},"mjx-maction[toggle]":{cursor:"pointer"},"mjx-status":{display:"block",position:"fixed",left:"1em",bottom:"1em","min-width":"25%",padding:".2em .4em",border:"1px solid #888","font-size":"90%","background-color":"#F8F8F8",color:"black"}},e.actions=new Map([["toggle",[function(t,e){t.adaptor.setAttribute(t.chtml,"toggle",t.node.attributes.get("selection"));var r=t.factory.jax.math,o=t.factory.jax.document,n=t.node;t.setEventHandler("click",(function(t){r.end.node||(r.start.node=r.end.node=r.typesetRoot,r.start.n=r.end.n=0),n.nextToggleSelection(),r.rerender(o),t.stopPropagation()}))},{}]],["tooltip",[function(t,e){var r=t.childNodes[1];if(r)if(r.node.isKind("mtext")){var o=r.node.getText();t.adaptor.setAttribute(t.chtml,"title",o)}else{var n=t.adaptor,i=n.append(t.chtml,t.html("mjx-tool",{style:{bottom:t.em(-t.dy),right:t.em(-t.dx)}},[t.html("mjx-tip")]));r.toCHTML(n.firstChild(i)),t.setEventHandler("mouseover",(function(r){e.stopTimers(t,e);var o=setTimeout((function(){return n.setStyle(i,"display","block")}),e.postDelay);e.hoverTimer.set(t,o),r.stopPropagation()})),t.setEventHandler("mouseout",(function(r){e.stopTimers(t,e);var o=setTimeout((function(){return n.setStyle(i,"display","")}),e.clearDelay);e.clearTimer.set(t,o),r.stopPropagation()}))}},s.TooltipData]],["statusline",[function(t,e){var r=t.childNodes[1];if(r&&r.node.isKind("mtext")){var o=t.adaptor,n=r.node.getText();o.setAttribute(t.chtml,"statusline",n),t.setEventHandler("mouseover",(function(r){if(null===e.status){var i=o.body(o.document);e.status=o.append(i,t.html("mjx-status",{},[t.text(n)]))}r.stopPropagation()})),t.setEventHandler("mouseout",(function(t){e.status&&(o.remove(e.status),e.status=null),t.stopPropagation()}))}},{status:null}]]]),e}(a.CommonMactionMixin(i.CHTMLWrapper));e.CHTMLmaction=h},4155:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmath=void 0;var a=r(6617),s=r(2057),l=r(304),h=r(3717),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){t.prototype.toCHTML.call(this,e);var r=this.chtml,o=this.adaptor;"block"===this.node.attributes.get("display")?(o.setAttribute(r,"display","true"),o.setAttribute(e,"display","true"),this.handleDisplay(e)):this.handleInline(e),o.addClass(r,"MJX-TEX")},e.prototype.handleDisplay=function(t){var e=this.adaptor,r=i(this.getAlignShift(),2),o=r[0],n=r[1];if("center"!==o&&e.setAttribute(t,"justify",o),this.bbox.pwidth===h.BBox.fullWidth){if(e.setAttribute(t,"width","full"),this.jax.table){var a=this.jax.table.getBBox(),s=a.L,l=a.w,c=a.R;"right"===o?c=Math.max(c||-n,-n):"left"===o?s=Math.max(s||n,n):"center"===o&&(l+=2*Math.abs(n));var u=this.em(Math.max(0,s+l+c));e.setStyle(t,"min-width",u),e.setStyle(this.jax.table.chtml,"min-width",u)}}else this.setIndent(this.chtml,o,n)},e.prototype.handleInline=function(t){var e=this.adaptor,r=e.getStyle(this.chtml,"margin-right");r&&(e.setStyle(this.chtml,"margin-right",""),e.setStyle(t,"margin-right",r),e.setStyle(t,"width","0"))},e.prototype.setChildPWidths=function(e,r,o){return void 0===r&&(r=null),void 0===o&&(o=!0),!!this.parent&&t.prototype.setChildPWidths.call(this,e,r,o)},e.kind=l.MmlMath.prototype.kind,e.styles={"mjx-math":{"line-height":0,"text-align":"left","text-indent":0,"font-style":"normal","font-weight":"normal","font-size":"100%","font-size-adjust":"none","letter-spacing":"normal","word-wrap":"normal","word-spacing":"normal","white-space":"nowrap",direction:"ltr",padding:"1px 0"},'mjx-container[jax="CHTML"][display="true"]':{display:"block","text-align":"center",margin:"1em 0"},'mjx-container[jax="CHTML"][display="true"][width="full"]':{display:"flex"},'mjx-container[jax="CHTML"][display="true"] mjx-math':{padding:0},'mjx-container[jax="CHTML"][justify="left"]':{"text-align":"left"},'mjx-container[jax="CHTML"][justify="right"]':{"text-align":"right"}},e}(s.CommonMathMixin(a.CHTMLWrapper));e.CHTMLmath=c},3215:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},a=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmenclose=void 0;var s=r(6617),l=r(6200),h=r(4458),c=r(4374),u=r(6914);function p(t,e){return Math.atan2(t,e).toFixed(3).replace(/\.?0+$/,"")}var d=p(h.ARROWDX,h.ARROWY),f=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e,r,o,n,a=this.adaptor,s=this.standardCHTMLnode(t),l=a.append(s,this.html("mjx-box"));this.renderChild?this.renderChild(this,l):this.childNodes[0].toCHTML(l);try{for(var c=i(Object.keys(this.notations)),u=c.next();!u.done;u=c.next()){var p=u.value,d=this.notations[p];!d.renderChild&&d.renderer(this,l)}}catch(t){e={error:t}}finally{try{u&&!u.done&&(r=c.return)&&r.call(c)}finally{if(e)throw e.error}}var f=this.getPadding();try{for(var m=i(h.sideNames),y=m.next();!y.done;y=m.next()){var v=y.value,b=h.sideIndex[v];f[b]>0&&a.setStyle(l,"padding-"+v,this.em(f[b]))}}catch(t){o={error:t}}finally{try{y&&!y.done&&(n=m.return)&&n.call(m)}finally{if(o)throw o.error}}},e.prototype.arrow=function(t,e,r,o,n){void 0===o&&(o=""),void 0===n&&(n=0);var i=this.getBBox().w,a={width:this.em(t)};i!==t&&(a.left=this.em((i-t)/2)),e&&(a.transform="rotate("+this.fixed(e)+"rad)");var s=this.html("mjx-arrow",{style:a},[this.html("mjx-aline"),this.html("mjx-rthead"),this.html("mjx-rbhead")]);return r&&(this.adaptor.append(s,this.html("mjx-lthead")),this.adaptor.append(s,this.html("mjx-lbhead")),this.adaptor.setAttribute(s,"double","true")),this.adjustArrow(s,r),this.moveArrow(s,o,n),s},e.prototype.adjustArrow=function(t,e){var r=this,o=this.thickness,n=this.arrowhead;if(n.x!==h.ARROWX||n.y!==h.ARROWY||n.dx!==h.ARROWDX||o!==h.THICKNESS){var i=a([o*n.x,o*n.y].map((function(t){return r.em(t)})),2),s=i[0],l=i[1],c=p(n.dx,n.y),u=a(this.adaptor.childNodes(t),5),d=u[0],f=u[1],m=u[2],y=u[3],v=u[4];this.adjustHead(f,[l,"0","1px",s],c),this.adjustHead(m,["1px","0",l,s],"-"+c),this.adjustHead(y,[l,s,"1px","0"],"-"+c),this.adjustHead(v,["1px",s,l,"0"],c),this.adjustLine(d,o,n.x,e)}},e.prototype.adjustHead=function(t,e,r){t&&(this.adaptor.setStyle(t,"border-width",e.join(" ")),this.adaptor.setStyle(t,"transform","skewX("+r+"rad)"))},e.prototype.adjustLine=function(t,e,r,o){this.adaptor.setStyle(t,"borderTop",this.em(e)+" solid"),this.adaptor.setStyle(t,"top",this.em(-e/2)),this.adaptor.setStyle(t,"right",this.em(e*(r-1))),o&&this.adaptor.setStyle(t,"left",this.em(e*(r-1)))},e.prototype.moveArrow=function(t,e,r){if(r){var o=this.adaptor.getStyle(t,"transform");this.adaptor.setStyle(t,"transform","translate"+e+"("+this.em(-r)+")"+(o?" "+o:""))}},e.prototype.adjustBorder=function(t){return this.thickness!==h.THICKNESS&&this.adaptor.setStyle(t,"borderWidth",this.em(this.thickness)),t},e.prototype.adjustThickness=function(t){return this.thickness!==h.THICKNESS&&this.adaptor.setStyle(t,"strokeWidth",this.fixed(this.thickness)),t},e.prototype.fixed=function(t,e){return void 0===e&&(e=3),Math.abs(t)<6e-4?"0":t.toFixed(e).replace(/\.?0+$/,"")},e.prototype.em=function(e){return t.prototype.em.call(this,e)},e.kind=c.MmlMenclose.prototype.kind,e.styles={"mjx-menclose":{position:"relative"},"mjx-menclose > mjx-dstrike":{display:"inline-block",left:0,top:0,position:"absolute","border-top":h.SOLID,"transform-origin":"top left"},"mjx-menclose > mjx-ustrike":{display:"inline-block",left:0,bottom:0,position:"absolute","border-top":h.SOLID,"transform-origin":"bottom left"},"mjx-menclose > mjx-hstrike":{"border-top":h.SOLID,position:"absolute",left:0,right:0,bottom:"50%",transform:"translateY("+u.em(h.THICKNESS/2)+")"},"mjx-menclose > mjx-vstrike":{"border-left":h.SOLID,position:"absolute",top:0,bottom:0,right:"50%",transform:"translateX("+u.em(h.THICKNESS/2)+")"},"mjx-menclose > mjx-rbox":{position:"absolute",top:0,bottom:0,right:0,left:0,border:h.SOLID,"border-radius":u.em(h.THICKNESS+h.PADDING)},"mjx-menclose > mjx-cbox":{position:"absolute",top:0,bottom:0,right:0,left:0,border:h.SOLID,"border-radius":"50%"},"mjx-menclose > mjx-arrow":{position:"absolute",left:0,bottom:"50%",height:0,width:0},"mjx-menclose > mjx-arrow > *":{display:"block",position:"absolute","transform-origin":"bottom","border-left":u.em(h.THICKNESS*h.ARROWX)+" solid","border-right":0,"box-sizing":"border-box"},"mjx-menclose > mjx-arrow > mjx-aline":{left:0,top:u.em(-h.THICKNESS/2),right:u.em(h.THICKNESS*(h.ARROWX-1)),height:0,"border-top":u.em(h.THICKNESS)+" solid","border-left":0},"mjx-menclose > mjx-arrow[double] > mjx-aline":{left:u.em(h.THICKNESS*(h.ARROWX-1)),height:0},"mjx-menclose > mjx-arrow > mjx-rthead":{transform:"skewX("+d+"rad)",right:0,bottom:"-1px","border-bottom":"1px solid transparent","border-top":u.em(h.THICKNESS*h.ARROWY)+" solid transparent"},"mjx-menclose > mjx-arrow > mjx-rbhead":{transform:"skewX(-"+d+"rad)","transform-origin":"top",right:0,top:"-1px","border-top":"1px solid transparent","border-bottom":u.em(h.THICKNESS*h.ARROWY)+" solid transparent"},"mjx-menclose > mjx-arrow > mjx-lthead":{transform:"skewX(-"+d+"rad)",left:0,bottom:"-1px","border-left":0,"border-right":u.em(h.THICKNESS*h.ARROWX)+" solid","border-bottom":"1px solid transparent","border-top":u.em(h.THICKNESS*h.ARROWY)+" solid transparent"},"mjx-menclose > mjx-arrow > mjx-lbhead":{transform:"skewX("+d+"rad)","transform-origin":"top",left:0,top:"-1px","border-left":0,"border-right":u.em(h.THICKNESS*h.ARROWX)+" solid","border-top":"1px solid transparent","border-bottom":u.em(h.THICKNESS*h.ARROWY)+" solid transparent"},"mjx-menclose > dbox":{position:"absolute",top:0,bottom:0,left:u.em(-1.5*h.PADDING),width:u.em(3*h.PADDING),border:u.em(h.THICKNESS)+" solid","border-radius":"50%","clip-path":"inset(0 0 0 "+u.em(1.5*h.PADDING)+")","box-sizing":"border-box"}},e.notations=new Map([h.Border("top"),h.Border("right"),h.Border("bottom"),h.Border("left"),h.Border2("actuarial","top","right"),h.Border2("madruwb","bottom","right"),h.DiagonalStrike("up",1),h.DiagonalStrike("down",-1),["horizontalstrike",{renderer:h.RenderElement("hstrike","Y"),bbox:function(t){return[0,t.padding,0,t.padding]}}],["verticalstrike",{renderer:h.RenderElement("vstrike","X"),bbox:function(t){return[t.padding,0,t.padding,0]}}],["box",{renderer:function(t,e){t.adaptor.setStyle(e,"border",t.em(t.thickness)+" solid")},bbox:h.fullBBox,border:h.fullBorder,remove:"left right top bottom"}],["roundedbox",{renderer:h.RenderElement("rbox"),bbox:h.fullBBox}],["circle",{renderer:h.RenderElement("cbox"),bbox:h.fullBBox}],["phasorangle",{renderer:function(t,e){var r=t.getBBox(),o=r.h,n=r.d,i=a(t.getArgMod(1.75*t.padding,o+n),2),s=i[0],l=i[1],h=t.thickness*Math.sin(s)*.9;t.adaptor.setStyle(e,"border-bottom",t.em(t.thickness)+" solid");var c=t.adjustBorder(t.html("mjx-ustrike",{style:{width:t.em(l),transform:"translateX("+t.em(h)+") rotate("+t.fixed(-s)+"rad)"}}));t.adaptor.append(t.chtml,c)},bbox:function(t){var e=t.padding/2,r=t.thickness;return[2*e,e,e+r,3*e+r]},border:function(t){return[0,0,t.thickness,0]},remove:"bottom"}],h.Arrow("up"),h.Arrow("down"),h.Arrow("left"),h.Arrow("right"),h.Arrow("updown"),h.Arrow("leftright"),h.DiagonalArrow("updiagonal"),h.DiagonalArrow("northeast"),h.DiagonalArrow("southeast"),h.DiagonalArrow("northwest"),h.DiagonalArrow("southwest"),h.DiagonalArrow("northeastsouthwest"),h.DiagonalArrow("northwestsoutheast"),["longdiv",{renderer:function(t,e){var r=t.adaptor;r.setStyle(e,"border-top",t.em(t.thickness)+" solid");var o=r.append(t.chtml,t.html("dbox")),n=t.thickness,i=t.padding;n!==h.THICKNESS&&r.setStyle(o,"border-width",t.em(n)),i!==h.PADDING&&(r.setStyle(o,"left",t.em(-1.5*i)),r.setStyle(o,"width",t.em(3*i)),r.setStyle(o,"clip-path","inset(0 0 0 "+t.em(1.5*i)+")"))},bbox:function(t){var e=t.padding,r=t.thickness;return[e+r,e,e,2*e+r/2]}}],["radical",{renderer:function(t,e){t.msqrt.toCHTML(e);var r=t.sqrtTRBL();t.adaptor.setStyle(t.msqrt.chtml,"margin",r.map((function(e){return t.em(-e)})).join(" "))},init:function(t){t.msqrt=t.createMsqrt(t.childNodes[0])},bbox:function(t){return t.sqrtTRBL()},renderChild:!0}]]),e}(l.CommonMencloseMixin(s.CHTMLWrapper));e.CHTMLmenclose=f},7047:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmfenced=void 0;var i=r(6617),a=r(1346),s=r(7451),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e=this.standardCHTMLnode(t);this.mrow.toCHTML(e)},e.kind=s.MmlMfenced.prototype.kind,e}(a.CommonMfencedMixin(i.CHTMLWrapper));e.CHTMLmfenced=l},7837:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,o=arguments.length;r *":{"font-size":"2000%"},"mjx-dbox":{display:"block","font-size":"5%"},"mjx-num":{display:"block","text-align":"center"},"mjx-den":{display:"block","text-align":"center"},"mjx-mfrac[bevelled] > mjx-num":{display:"inline-block"},"mjx-mfrac[bevelled] > mjx-den":{display:"inline-block"},'mjx-den[align="right"], mjx-num[align="right"]':{"text-align":"right"},'mjx-den[align="left"], mjx-num[align="left"]':{"text-align":"left"},"mjx-nstrut":{display:"inline-block",height:".054em",width:0,"vertical-align":"-.054em"},'mjx-nstrut[type="d"]':{height:".217em","vertical-align":"-.217em"},"mjx-dstrut":{display:"inline-block",height:".505em",width:0},'mjx-dstrut[type="d"]':{height:".726em"},"mjx-line":{display:"block","box-sizing":"border-box","min-height":"1px",height:".06em","border-top":".06em solid",margin:".06em -.1em",overflow:"hidden"},'mjx-line[type="d"]':{margin:".18em -.1em"}},e}(s.CommonMfracMixin(a.CHTMLWrapper));e.CHTMLmfrac=h},1315:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmglyph=void 0;var i=r(6617),a=r(7969),s=r(910),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e=this.standardCHTMLnode(t),r=this.node.attributes.getList("src","alt"),o=r.src,n=r.alt,i={width:this.em(this.width),height:this.em(this.height)};this.valign&&(i.verticalAlign=this.em(this.valign));var a=this.html("img",{src:o,style:i,alt:n,title:n});this.adaptor.append(e,a)},e.kind=s.MmlMglyph.prototype.kind,e.styles={"mjx-mglyph > img":{display:"inline-block",border:0,padding:0}},e}(a.CommonMglyphMixin(i.CHTMLWrapper));e.CHTMLmglyph=l},3271:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmi=void 0;var i=r(6617),a=r(1419),s=r(7754),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=s.MmlMi.prototype.kind,e}(a.CommonMiMixin(i.CHTMLWrapper));e.CHTMLmi=l},1096:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmmultiscripts=void 0;var a=r(513),s=r(9906),l=r(7764),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e=this.standardCHTMLnode(t),r=this.scriptData,o=this.combinePrePost(r.sub,r.psub),n=this.combinePrePost(r.sup,r.psup),a=i(this.getUVQ(o,n),2),s=a[0],l=a[1];r.numPrescripts&&this.addScripts(s,-l,!0,r.psub,r.psup,this.firstPrescript,r.numPrescripts),this.childNodes[0].toCHTML(e),r.numScripts&&this.addScripts(s,-l,!1,r.sub,r.sup,1,r.numScripts)},e.prototype.addScripts=function(t,e,r,o,n,i,a){var s=this.adaptor,l=t-n.d+(e-o.h),h=t<0&&0===e?o.h+t:t,c=l>0?{style:{height:this.em(l)}}:{},u=h?{style:{"vertical-align":this.em(h)}}:{},p=this.html("mjx-row"),d=this.html("mjx-row",c),f=this.html("mjx-row"),m="mjx-"+(r?"pre":"")+"scripts";s.append(this.chtml,this.html(m,u,[p,d,f]));for(var y=i+2*a;i mjx-row > mjx-cell":{"text-align":"right"}},e}(s.CommonMmultiscriptsMixin(a.CHTMLmsubsup));e.CHTMLmmultiscripts=h},7013:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmn=void 0;var i=r(6617),a=r(2304),s=r(3235),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=s.MmlMn.prototype.kind,e}(a.CommonMnMixin(i.CHTMLWrapper));e.CHTMLmn=l},3292:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmo=void 0;var a=r(6617),s=r(437),l=r(9946),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e,r,o=this.node.attributes,n=o.get("symmetric")&&2!==this.stretch.dir,a=0!==this.stretch.dir;a&&null===this.size&&this.getStretchedVariant([]);var s=this.standardCHTMLnode(t);if(a&&this.size<0)this.stretchHTML(s);else{if(n||o.get("largeop")){var l=this.em(this.getCenterOffset());"0"!==l&&this.adaptor.setStyle(s,"verticalAlign",l)}this.node.getProperty("mathaccent")&&(this.adaptor.setStyle(s,"width","0"),this.adaptor.setStyle(s,"margin-left",this.em(this.getAccentOffset())));try{for(var h=i(this.childNodes),c=h.next();!c.done;c=h.next()){c.value.toCHTML(s)}}catch(t){e={error:t}}finally{try{c&&!c.done&&(r=h.return)&&r.call(h)}finally{if(e)throw e.error}}}},e.prototype.stretchHTML=function(t){var e=this.getText().codePointAt(0),r=this.stretch;r.used=!0;var o=r.stretch,n=[];o[0]&&n.push(this.html("mjx-beg",{},[this.html("mjx-c")])),n.push(this.html("mjx-ext",{},[this.html("mjx-c")])),4===o.length&&n.push(this.html("mjx-mid",{},[this.html("mjx-c")]),this.html("mjx-ext",{},[this.html("mjx-c")])),o[2]&&n.push(this.html("mjx-end",{},[this.html("mjx-c")]));var i={},a=this.bbox,l=a.h,h=a.d,c=a.w;1===r.dir?(n.push(this.html("mjx-mark")),i.height=this.em(l+h),i.verticalAlign=this.em(-h)):i.width=this.em(c);var u=s.DirectionVH[r.dir],p={class:this.char(r.c||e),style:i},d=this.html("mjx-stretchy-"+u,p,n);this.adaptor.append(t,d)},e.kind=l.MmlMo.prototype.kind,e.styles={"mjx-stretchy-h":{display:"inline-table",width:"100%"},"mjx-stretchy-h > *":{display:"table-cell",width:0},"mjx-stretchy-h > * > mjx-c":{display:"inline-block",transform:"scalex(1.0000001)"},"mjx-stretchy-h > * > mjx-c::before":{display:"inline-block",width:"initial"},"mjx-stretchy-h > mjx-ext":{overflow:"hidden",width:"100%"},"mjx-stretchy-h > mjx-ext > mjx-c::before":{transform:"scalex(500)"},"mjx-stretchy-h > mjx-ext > mjx-c":{width:0},"mjx-stretchy-h > mjx-beg > mjx-c":{"margin-right":"-.1em"},"mjx-stretchy-h > mjx-end > mjx-c":{"margin-left":"-.1em"},"mjx-stretchy-v":{display:"inline-block"},"mjx-stretchy-v > *":{display:"block"},"mjx-stretchy-v > mjx-beg":{height:0},"mjx-stretchy-v > mjx-end > mjx-c":{display:"block"},"mjx-stretchy-v > * > mjx-c":{transform:"scaley(1.0000001)","transform-origin":"left center",overflow:"hidden"},"mjx-stretchy-v > mjx-ext":{display:"block",height:"100%","box-sizing":"border-box",border:"0px solid transparent",overflow:"hidden"},"mjx-stretchy-v > mjx-ext > mjx-c::before":{width:"initial","box-sizing":"border-box"},"mjx-stretchy-v > mjx-ext > mjx-c":{transform:"scaleY(500) translateY(.075em)",overflow:"visible"},"mjx-mark":{display:"inline-block",height:"0px"}},e}(s.CommonMoMixin(a.CHTMLWrapper));e.CHTMLmo=h},7215:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmpadded=void 0;var s=r(6617),l=r(7481),h=r(189),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e,r,o=this.standardCHTMLnode(t),n=[],s={},l=i(this.getDimens(),9),h=l[2],c=l[3],u=l[4],p=l[5],d=l[6],f=l[7],m=l[8];if(p&&(s.width=this.em(h+p)),(c||u)&&(s.margin=this.em(c)+" 0 "+this.em(u)),d+m||f){s.position="relative";var y=this.html("mjx-rbox",{style:{left:this.em(d+m),top:this.em(-f)}});d+m&&this.childNodes[0].getBBox().pwidth&&(this.adaptor.setAttribute(y,"width","full"),this.adaptor.setStyle(y,"left",this.em(d))),n.push(y)}o=this.adaptor.append(o,this.html("mjx-block",{style:s},n));try{for(var v=a(this.childNodes),b=v.next();!b.done;b=v.next()){b.value.toCHTML(n[0]||o)}}catch(t){e={error:t}}finally{try{b&&!b.done&&(r=v.return)&&r.call(v)}finally{if(e)throw e.error}}},e.kind=h.MmlMpadded.prototype.kind,e.styles={"mjx-mpadded":{display:"inline-block"},"mjx-rbox":{display:"inline-block",position:"relative"}},e}(l.CommonMpaddedMixin(s.CHTMLWrapper));e.CHTMLmpadded=c},7111:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmroot=void 0;var a=r(5437),s=r(5997),l=r(4664),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.addRoot=function(t,e,r,o){e.toCHTML(t);var n=i(this.getRootDimens(r,o),3),a=n[0],s=n[1],l=n[2];this.adaptor.setStyle(t,"verticalAlign",this.em(s)),this.adaptor.setStyle(t,"width",this.em(a)),l&&this.adaptor.setStyle(this.adaptor.firstChild(t),"paddingLeft",this.em(l))},e.kind=l.MmlMroot.prototype.kind,e}(s.CommonMrootMixin(a.CHTMLmsqrt));e.CHTMLmroot=h},3126:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLinferredMrow=e.CHTMLmrow=void 0;var a=r(6617),s=r(9323),l=r(9323),h=r(1691),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e,r,o=this.node.isInferred?this.chtml=t:this.standardCHTMLnode(t),n=!1;try{for(var a=i(this.childNodes),s=a.next();!s.done;s=a.next()){var l=s.value;l.toCHTML(o),l.bbox.w<0&&(n=!0)}}catch(t){e={error:t}}finally{try{s&&!s.done&&(r=a.return)&&r.call(a)}finally{if(e)throw e.error}}if(n){var h=this.getBBox().w;h&&(this.adaptor.setStyle(o,"width",this.em(Math.max(0,h))),h<0&&this.adaptor.setStyle(o,"marginRight",this.em(h)))}},e.kind=h.MmlMrow.prototype.kind,e}(s.CommonMrowMixin(a.CHTMLWrapper));e.CHTMLmrow=c;var u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=h.MmlInferredMrow.prototype.kind,e}(l.CommonInferredMrowMixin(c));e.CHTMLinferredMrow=u},9821:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLms=void 0;var i=r(6617),a=r(6920),s=r(4042),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=s.MmlMs.prototype.kind,e}(a.CommonMsMixin(i.CHTMLWrapper));e.CHTMLms=l},6024:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmspace=void 0;var i=r(6617),a=r(37),s=r(1465),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e=this.standardCHTMLnode(t),r=this.getBBox(),o=r.w,n=r.h,i=r.d;o<0&&(this.adaptor.setStyle(e,"marginRight",this.em(o)),o=0),o&&this.adaptor.setStyle(e,"width",this.em(o)),(n=Math.max(0,n+i))&&this.adaptor.setStyle(e,"height",this.em(Math.max(0,n))),i&&this.adaptor.setStyle(e,"verticalAlign",this.em(-i))},e.kind=s.MmlMspace.prototype.kind,e}(a.CommonMspaceMixin(i.CHTMLWrapper));e.CHTMLmspace=l},5437:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmsqrt=void 0;var a=r(6617),s=r(222),l=r(4655),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e,r,o,n,a=this.childNodes[this.surd],s=this.childNodes[this.base],l=a.getBBox(),h=s.getBBox(),c=i(this.getPQ(l),2)[1],u=this.font.params.rule_thickness,p=h.h+c+u,d=this.standardCHTMLnode(t);null!=this.root&&(o=this.adaptor.append(d,this.html("mjx-root")),n=this.childNodes[this.root]);var f=this.adaptor.append(d,this.html("mjx-sqrt",{},[e=this.html("mjx-surd"),r=this.html("mjx-box",{style:{paddingTop:this.em(c)}})]));this.addRoot(o,n,l,p),a.toCHTML(e),s.toCHTML(r),a.size<0&&this.adaptor.addClass(f,"mjx-tall")},e.prototype.addRoot=function(t,e,r,o){},e.kind=l.MmlMsqrt.prototype.kind,e.styles={"mjx-root":{display:"inline-block","white-space":"nowrap"},"mjx-surd":{display:"inline-block","vertical-align":"top"},"mjx-sqrt":{display:"inline-block","padding-top":".07em"},"mjx-sqrt > mjx-box":{"border-top":".07em solid"},"mjx-sqrt.mjx-tall > mjx-box":{"padding-left":".3em","margin-left":"-.3em"}},e}(s.CommonMsqrtMixin(a.CHTMLWrapper));e.CHTMLmsqrt=h},513:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmsubsup=e.CHTMLmsup=e.CHTMLmsub=void 0;var a=r(7322),s=r(3069),l=r(3069),h=r(3069),c=r(5857),u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=c.MmlMsub.prototype.kind,e}(s.CommonMsubMixin(a.CHTMLscriptbase));e.CHTMLmsub=u;var p=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=c.MmlMsup.prototype.kind,e}(l.CommonMsupMixin(a.CHTMLscriptbase));e.CHTMLmsup=p;var d=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.markUsed=function(){t.prototype.markUsed.call(this),e.used=!0},e.prototype.toCHTML=function(t){var e=this.adaptor,r=this.standardCHTMLnode(t),o=i([this.baseChild,this.supChild,this.subChild],3),n=o[0],a=o[1],s=o[2],l=i(this.getUVQ(),3),h=l[1],c=l[2],u={"vertical-align":this.em(h)};n.toCHTML(r);var p=e.append(r,this.html("mjx-script",{style:u}));a.toCHTML(p),e.append(p,this.html("mjx-spacer",{style:{"margin-top":this.em(c)}})),s.toCHTML(p);var d=this.getAdjustedIc();d&&e.setStyle(a.chtml,"marginLeft",this.em(d/a.bbox.rscale)),this.baseRemoveIc&&e.setStyle(p,"marginLeft",this.em(-this.baseIc))},e.kind=c.MmlMsubsup.prototype.kind,e.styles={"mjx-script":{display:"inline-block","padding-right":".05em","padding-left":".033em"},"mjx-script > *":{display:"block"}},e}(h.CommonMsubsupMixin(a.CHTMLscriptbase));e.CHTMLmsubsup=d},6918:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},a=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmtable=void 0;var s=r(6617),l=r(8589),h=r(4859),c=r(6720),u=function(t){function e(e,r,o){void 0===o&&(o=null);var n=t.call(this,e,r,o)||this;return n.itable=n.html("mjx-itable"),n.labels=n.html("mjx-itable"),n}return n(e,t),e.prototype.getAlignShift=function(){var e=t.prototype.getAlignShift.call(this);return this.isTop||(e[1]=0),e},e.prototype.toCHTML=function(t){var e,r,o=this.standardCHTMLnode(t);this.adaptor.append(o,this.html("mjx-table",{},[this.itable]));try{for(var n=i(this.childNodes),a=n.next();!a.done;a=n.next()){a.value.toCHTML(this.itable)}}catch(t){e={error:t}}finally{try{a&&!a.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}this.padRows(),this.handleColumnSpacing(),this.handleColumnLines(),this.handleColumnWidths(),this.handleRowSpacing(),this.handleRowLines(),this.handleRowHeights(),this.handleFrame(),this.handleWidth(),this.handleLabels(),this.handleAlign(),this.handleJustify(),this.shiftColor()},e.prototype.shiftColor=function(){var t=this.adaptor,e=t.getStyle(this.chtml,"backgroundColor");e&&(t.setStyle(this.chtml,"backgroundColor",""),t.setStyle(this.itable,"backgroundColor",e))},e.prototype.padRows=function(){var t,e,r=this.adaptor;try{for(var o=i(r.childNodes(this.itable)),n=o.next();!n.done;n=o.next())for(var a=n.value;r.childNodes(a).length1&&"0.4em"!==m||s&&1===u)&&this.adaptor.setStyle(v,"paddingLeft",m),(u1&&"0.215em"!==p||s&&1===l)&&this.adaptor.setStyle(y.chtml,"paddingTop",p),(l mjx-itable":{"vertical-align":"middle","text-align":"left","box-sizing":"border-box"},"mjx-labels > mjx-itable":{position:"absolute",top:0},'mjx-mtable[justify="left"]':{"text-align":"left"},'mjx-mtable[justify="right"]':{"text-align":"right"},'mjx-mtable[justify="left"][side="left"]':{"padding-right":"0 ! important"},'mjx-mtable[justify="left"][side="right"]':{"padding-left":"0 ! important"},'mjx-mtable[justify="right"][side="left"]':{"padding-right":"0 ! important"},'mjx-mtable[justify="right"][side="right"]':{"padding-left":"0 ! important"},"mjx-mtable[align]":{"vertical-align":"baseline"},'mjx-mtable[align="top"] > mjx-table':{"vertical-align":"top"},'mjx-mtable[align="bottom"] > mjx-table':{"vertical-align":"bottom"},'mjx-mtable[side="right"] mjx-labels':{"min-width":"100%"}},e}(l.CommonMtableMixin(s.CHTMLWrapper));e.CHTMLmtable=u},8709:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmtd=void 0;var i=r(6617),a=r(7805),s=r(2321),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){t.prototype.toCHTML.call(this,e);var r=this.node.attributes.get("rowalign"),o=this.node.attributes.get("columnalign");r!==this.parent.node.attributes.get("rowalign")&&this.adaptor.setAttribute(this.chtml,"rowalign",r),"center"===o||"mlabeledtr"===this.parent.kind&&this===this.parent.childNodes[0]&&o===this.parent.parent.node.attributes.get("side")||this.adaptor.setStyle(this.chtml,"textAlign",o),this.parent.parent.node.getProperty("useHeight")&&this.adaptor.append(this.chtml,this.html("mjx-tstrut"))},e.kind=s.MmlMtd.prototype.kind,e.styles={"mjx-mtd":{display:"table-cell","text-align":"center",padding:".215em .4em"},"mjx-mtd:first-child":{"padding-left":0},"mjx-mtd:last-child":{"padding-right":0},"mjx-mtable > * > mjx-itable > *:first-child > mjx-mtd":{"padding-top":0},"mjx-mtable > * > mjx-itable > *:last-child > mjx-mtd":{"padding-bottom":0},"mjx-tstrut":{display:"inline-block",height:"1em","vertical-align":"-.25em"},'mjx-labels[align="left"] > mjx-mtr > mjx-mtd':{"text-align":"left"},'mjx-labels[align="right"] > mjx-mtr > mjx-mtd':{"text-align":"right"},'mjx-mtr mjx-mtd[rowalign="top"], mjx-mlabeledtr mjx-mtd[rowalign="top"]':{"vertical-align":"top"},'mjx-mtr mjx-mtd[rowalign="center"], mjx-mlabeledtr mjx-mtd[rowalign="center"]':{"vertical-align":"middle"},'mjx-mtr mjx-mtd[rowalign="bottom"], mjx-mlabeledtr mjx-mtd[rowalign="bottom"]':{"vertical-align":"bottom"},'mjx-mtr mjx-mtd[rowalign="baseline"], mjx-mlabeledtr mjx-mtd[rowalign="baseline"]':{"vertical-align":"baseline"},'mjx-mtr mjx-mtd[rowalign="axis"], mjx-mlabeledtr mjx-mtd[rowalign="axis"]':{"vertical-align":".25em"}},e}(a.CommonMtdMixin(i.CHTMLWrapper));e.CHTMLmtd=l},6359:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmtext=void 0;var i=r(6617),a=r(8325),s=r(6277),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=s.MmlMtext.prototype.kind,e}(a.CommonMtextMixin(i.CHTMLWrapper));e.CHTMLmtext=l},7500:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmlabeledtr=e.CHTMLmtr=void 0;var i=r(6617),a=r(4818),s=r(4818),l=r(4393),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){t.prototype.toCHTML.call(this,e);var r=this.node.attributes.get("rowalign");"baseline"!==r&&this.adaptor.setAttribute(this.chtml,"rowalign",r)},e.kind=l.MmlMtr.prototype.kind,e.styles={"mjx-mtr":{display:"table-row"},'mjx-mtr[rowalign="top"] > mjx-mtd':{"vertical-align":"top"},'mjx-mtr[rowalign="center"] > mjx-mtd':{"vertical-align":"middle"},'mjx-mtr[rowalign="bottom"] > mjx-mtd':{"vertical-align":"bottom"},'mjx-mtr[rowalign="baseline"] > mjx-mtd':{"vertical-align":"baseline"},'mjx-mtr[rowalign="axis"] > mjx-mtd':{"vertical-align":".25em"}},e}(a.CommonMtrMixin(i.CHTMLWrapper));e.CHTMLmtr=h;var c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){t.prototype.toCHTML.call(this,e);var r=this.adaptor.firstChild(this.chtml);if(r){this.adaptor.remove(r);var o=this.node.attributes.get("rowalign"),n="baseline"!==o&&"axis"!==o?{rowalign:o}:{},i=this.html("mjx-mtr",n,[r]);h.used=!0,this.adaptor.append(this.parent.labels,i)}},e.kind=l.MmlMlabeledtr.prototype.kind,e.styles={"mjx-mlabeledtr":{display:"table-row"},'mjx-mlabeledtr[rowalign="top"] > mjx-mtd':{"vertical-align":"top"},'mjx-mlabeledtr[rowalign="center"] > mjx-mtd':{"vertical-align":"middle"},'mjx-mlabeledtr[rowalign="bottom"] > mjx-mtd':{"vertical-align":"bottom"},'mjx-mlabeledtr[rowalign="baseline"] > mjx-mtd':{"vertical-align":"baseline"},'mjx-mlabeledtr[rowalign="axis"] > mjx-mtd':{"vertical-align":".25em"}},e}(s.CommonMlabeledtrMixin(h));e.CHTMLmlabeledtr=c},6577:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLmunderover=e.CHTMLmover=e.CHTMLmunder=void 0;var i=r(513),a=r(9690),s=r(9690),l=r(9690),h=r(3102),c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){if(this.hasMovableLimits())return t.prototype.toCHTML.call(this,e),void this.adaptor.setAttribute(this.chtml,"limits","false");this.chtml=this.standardCHTMLnode(e);var r=this.adaptor.append(this.adaptor.append(this.chtml,this.html("mjx-row")),this.html("mjx-base")),o=this.adaptor.append(this.adaptor.append(this.chtml,this.html("mjx-row")),this.html("mjx-under"));this.baseChild.toCHTML(r),this.scriptChild.toCHTML(o);var n=this.baseChild.getBBox(),i=this.scriptChild.getBBox(),a=this.getUnderKV(n,i)[0],s=this.isLineBelow?0:this.getDelta(!0);this.adaptor.setStyle(o,"paddingTop",this.em(a)),this.setDeltaW([r,o],this.getDeltaW([n,i],[0,-s])),this.adjustUnderDepth(o,i)},e.kind=h.MmlMunder.prototype.kind,e.styles={"mjx-over":{"text-align":"left"},'mjx-munder:not([limits="false"])':{display:"inline-table"},"mjx-munder > mjx-row":{"text-align":"left"},"mjx-under":{"padding-bottom":".1em"}},e}(a.CommonMunderMixin(i.CHTMLmsub));e.CHTMLmunder=c;var u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){if(this.hasMovableLimits())return t.prototype.toCHTML.call(this,e),void this.adaptor.setAttribute(this.chtml,"limits","false");this.chtml=this.standardCHTMLnode(e);var r=this.adaptor.append(this.chtml,this.html("mjx-over")),o=this.adaptor.append(this.chtml,this.html("mjx-base"));this.scriptChild.toCHTML(r),this.baseChild.toCHTML(o);var n=this.scriptChild.getBBox(),i=this.baseChild.getBBox(),a=this.getOverKU(i,n)[0],s=this.isLineAbove?0:this.getDelta();this.adaptor.setStyle(r,"paddingBottom",this.em(a)),this.setDeltaW([o,r],this.getDeltaW([i,n],[0,s])),this.adjustOverDepth(r,n)},e.kind=h.MmlMover.prototype.kind,e.styles={'mjx-mover:not([limits="false"])':{"padding-top":".1em"},'mjx-mover:not([limits="false"]) > *':{display:"block","text-align":"left"}},e}(s.CommonMoverMixin(i.CHTMLmsup));e.CHTMLmover=u;var p=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){if(this.hasMovableLimits())return t.prototype.toCHTML.call(this,e),void this.adaptor.setAttribute(this.chtml,"limits","false");this.chtml=this.standardCHTMLnode(e);var r=this.adaptor.append(this.chtml,this.html("mjx-over")),o=this.adaptor.append(this.adaptor.append(this.chtml,this.html("mjx-box")),this.html("mjx-munder")),n=this.adaptor.append(this.adaptor.append(o,this.html("mjx-row")),this.html("mjx-base")),i=this.adaptor.append(this.adaptor.append(o,this.html("mjx-row")),this.html("mjx-under"));this.overChild.toCHTML(r),this.baseChild.toCHTML(n),this.underChild.toCHTML(i);var a=this.overChild.getBBox(),s=this.baseChild.getBBox(),l=this.underChild.getBBox(),h=this.getOverKU(s,a)[0],c=this.getUnderKV(s,l)[0],u=this.getDelta();this.adaptor.setStyle(r,"paddingBottom",this.em(h)),this.adaptor.setStyle(i,"paddingTop",this.em(c)),this.setDeltaW([n,i,r],this.getDeltaW([s,l,a],[0,this.isLineBelow?0:-u,this.isLineAbove?0:u])),this.adjustOverDepth(r,a),this.adjustUnderDepth(i,l)},e.kind=h.MmlMunderover.prototype.kind,e.styles={'mjx-munderover:not([limits="false"])':{"padding-top":".1em"},'mjx-munderover:not([limits="false"]) > *':{display:"block"}},e}(l.CommonMunderoverMixin(i.CHTMLmsubsup));e.CHTMLmunderover=p},7322:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLscriptbase=void 0;var s=r(6617),l=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){this.chtml=this.standardCHTMLnode(t);var e=i(this.getOffset(),2),r=e[0],o=e[1],n=r-(this.baseRemoveIc?this.baseIc:0),a={"vertical-align":this.em(o)};n&&(a["margin-left"]=this.em(n)),this.baseChild.toCHTML(this.chtml),this.scriptChild.toCHTML(this.adaptor.append(this.chtml,this.html("mjx-script",{style:a})))},e.prototype.setDeltaW=function(t,e){for(var r=0;r=0||this.adaptor.setStyle(t,"marginBottom",this.em(e.d*e.rscale))},e.prototype.adjustUnderDepth=function(t,e){var r,o;if(!(e.d>=0)){var n=this.adaptor,i=this.em(e.d),s=this.html("mjx-box",{style:{"margin-bottom":i,"vertical-align":i}});try{for(var l=a(n.childNodes(n.firstChild(t))),h=l.next();!h.done;h=l.next()){var c=h.value;n.append(s,c)}}catch(t){r={error:t}}finally{try{h&&!h.done&&(o=l.return)&&o.call(l)}finally{if(r)throw r.error}}n.append(n.firstChild(t),s)}},e.kind="scriptbase",e}(r(7091).CommonScriptbaseMixin(s.CHTMLWrapper));e.CHTMLscriptbase=l},7795:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CHTMLxml=e.CHTMLannotationXML=e.CHTMLannotation=e.CHTMLsemantics=void 0;var i=r(6617),a=r(3191),s=r(9167),l=r(8921),h=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){var e=this.standardCHTMLnode(t);this.childNodes.length&&this.childNodes[0].toCHTML(e)},e.kind=s.MmlSemantics.prototype.kind,e}(a.CommonSemanticsMixin(i.CHTMLWrapper));e.CHTMLsemantics=h;var c=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(e){t.prototype.toCHTML.call(this,e)},e.prototype.computeBBox=function(){return this.bbox},e.kind=s.MmlAnnotation.prototype.kind,e}(i.CHTMLWrapper);e.CHTMLannotation=c;var u=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.kind=s.MmlAnnotationXML.prototype.kind,e.styles={"mjx-annotation-xml":{"font-family":"initial","line-height":"normal"}},e}(i.CHTMLWrapper);e.CHTMLannotationXML=u;var p=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.toCHTML=function(t){this.chtml=this.adaptor.append(t,this.adaptor.clone(this.node.getXML()))},e.prototype.computeBBox=function(t,e){void 0===e&&(e=!1);var r=this.jax.measureXMLnode(this.node.getXML()),o=r.w,n=r.h,i=r.d;t.w=o,t.h=n,t.d=i},e.prototype.getStyles=function(){},e.prototype.getScale=function(){},e.prototype.getVariant=function(){},e.kind=l.XMLNode.prototype.kind,e.autoStyle=!1,e}(i.CHTMLWrapper);e.CHTMLxml=p},9250:function(t,e,r){var o=this&&this.__assign||function(){return(o=Object.assign||function(t){for(var e,r=1,o=arguments.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.FontData=e.NOSTRETCH=e.H=e.V=void 0;var s=r(9077);e.V=1,e.H=2,e.NOSTRETCH={dir:0};var l=function(){function t(t){var e,r,l,h;void 0===t&&(t=null),this.variant={},this.delimiters={},this.cssFontMap={},this.remapChars={},this.skewIcFactor=.75;var c=this.constructor;this.options=s.userOptions(s.defaultOptions({},c.OPTIONS),t),this.params=o({},c.defaultParams),this.sizeVariants=i([],n(c.defaultSizeVariants)),this.stretchVariants=i([],n(c.defaultStretchVariants)),this.cssFontMap=o({},c.defaultCssFonts);try{for(var u=a(Object.keys(this.cssFontMap)),p=u.next();!p.done;p=u.next()){var d=p.value;"unknown"===this.cssFontMap[d][0]&&(this.cssFontMap[d][0]=this.options.unknownFamily)}}catch(t){e={error:t}}finally{try{p&&!p.done&&(r=u.return)&&r.call(u)}finally{if(e)throw e.error}}this.cssFamilyPrefix=c.defaultCssFamilyPrefix,this.createVariants(c.defaultVariants),this.defineDelimiters(c.defaultDelimiters);try{for(var f=a(Object.keys(c.defaultChars)),m=f.next();!m.done;m=f.next()){var y=m.value;this.defineChars(y,c.defaultChars[y])}}catch(t){l={error:t}}finally{try{m&&!m.done&&(h=f.return)&&h.call(f)}finally{if(l)throw l.error}}this.defineRemap("accent",c.defaultAccentMap),this.defineRemap("mo",c.defaultMoMap),this.defineRemap("mn",c.defaultMnMap)}return t.charOptions=function(t,e){var r=t[e];return 3===r.length&&(r[3]={}),r[3]},Object.defineProperty(t.prototype,"styles",{get:function(){return this._styles},set:function(t){this._styles=t},enumerable:!1,configurable:!0}),t.prototype.createVariant=function(t,e,r){void 0===e&&(e=null),void 0===r&&(r=null);var o={linked:[],chars:e?Object.create(this.variant[e].chars):{}};r&&this.variant[r]&&(Object.assign(o.chars,this.variant[r].chars),this.variant[r].linked.push(o.chars),o.chars=Object.create(o.chars)),this.remapSmpChars(o.chars,t),this.variant[t]=o},t.prototype.remapSmpChars=function(t,e){var r,o,i,s,l=this.constructor;if(l.VariantSmp[e]){var h=l.SmpRemap,c=[null,null,l.SmpRemapGreekU,l.SmpRemapGreekL];try{for(var u=a(l.SmpRanges),p=u.next();!p.done;p=u.next()){var d=n(p.value,3),f=d[0],m=d[1],y=d[2],v=l.VariantSmp[e][f];if(v){for(var b=m;b<=y;b++)if(930!==b){var x=v+b-m;t[b]=this.smpChar(h[x]||x)}if(c[f])try{for(var g=(i=void 0,a(Object.keys(c[f]).map((function(t){return parseInt(t)})))),M=g.next();!M.done;M=g.next()){t[b=M.value]=this.smpChar(v+c[f][b])}}catch(t){i={error:t}}finally{try{M&&!M.done&&(s=g.return)&&s.call(g)}finally{if(i)throw i.error}}}}}catch(t){r={error:t}}finally{try{p&&!p.done&&(o=u.return)&&o.call(u)}finally{if(r)throw r.error}}}"bold"===e&&(t[988]=this.smpChar(120778),t[989]=this.smpChar(120779))},t.prototype.smpChar=function(t){return[,,,{smp:t}]},t.prototype.createVariants=function(t){var e,r;try{for(var o=a(t),n=o.next();!n.done;n=o.next()){var i=n.value;this.createVariant(i[0],i[1],i[2])}}catch(t){e={error:t}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(e)throw e.error}}},t.prototype.defineChars=function(t,e){var r,o,n=this.variant[t];Object.assign(n.chars,e);try{for(var i=a(n.linked),s=i.next();!s.done;s=i.next()){var l=s.value;Object.assign(l,e)}}catch(t){r={error:t}}finally{try{s&&!s.done&&(o=i.return)&&o.call(i)}finally{if(r)throw r.error}}},t.prototype.defineDelimiters=function(t){Object.assign(this.delimiters,t)},t.prototype.defineRemap=function(t,e){this.remapChars.hasOwnProperty(t)||(this.remapChars[t]={}),Object.assign(this.remapChars[t],e)},t.prototype.getDelimiter=function(t){return this.delimiters[t]},t.prototype.getSizeVariant=function(t,e){return this.delimiters[t].variants&&(e=this.delimiters[t].variants[e]),this.sizeVariants[e]},t.prototype.getStretchVariant=function(t,e){return this.stretchVariants[this.delimiters[t].stretchv?this.delimiters[t].stretchv[e]:0]},t.prototype.getChar=function(t,e){return this.variant[t].chars[e]},t.prototype.getVariant=function(t){return this.variant[t]},t.prototype.getCssFont=function(t){return this.cssFontMap[t]||["serif",!1,!1]},t.prototype.getFamily=function(t){return this.cssFamilyPrefix?this.cssFamilyPrefix+", "+t:t},t.prototype.getRemappedChar=function(t,e){return(this.remapChars[t]||{})[e]},t.OPTIONS={unknownFamily:"serif"},t.defaultVariants=[["normal"],["bold","normal"],["italic","normal"],["bold-italic","italic","bold"],["double-struck","bold"],["fraktur","normal"],["bold-fraktur","bold","fraktur"],["script","italic"],["bold-script","bold-italic","script"],["sans-serif","normal"],["bold-sans-serif","bold","sans-serif"],["sans-serif-italic","italic","sans-serif"],["sans-serif-bold-italic","bold-italic","bold-sans-serif"],["monospace","normal"]],t.defaultCssFonts={normal:["unknown",!1,!1],bold:["unknown",!1,!0],italic:["unknown",!0,!1],"bold-italic":["unknown",!0,!0],"double-struck":["unknown",!1,!0],fraktur:["unknown",!1,!1],"bold-fraktur":["unknown",!1,!0],script:["cursive",!1,!1],"bold-script":["cursive",!1,!0],"sans-serif":["sans-serif",!1,!1],"bold-sans-serif":["sans-serif",!1,!0],"sans-serif-italic":["sans-serif",!0,!1],"sans-serif-bold-italic":["sans-serif",!0,!0],monospace:["monospace",!1,!1]},t.defaultCssFamilyPrefix="",t.VariantSmp={bold:[119808,119834,120488,120514,120782],italic:[119860,119886,120546,120572],"bold-italic":[119912,119938,120604,120630],script:[119964,119990],"bold-script":[120016,120042],fraktur:[120068,120094],"double-struck":[120120,120146,,,120792],"bold-fraktur":[120172,120198],"sans-serif":[120224,120250,,,120802],"bold-sans-serif":[120276,120302,120662,120688,120812],"sans-serif-italic":[120328,120354],"sans-serif-bold-italic":[120380,120406,120720,120746],monospace:[120432,120458,,,120822]},t.SmpRanges=[[0,65,90],[1,97,122],[2,913,937],[3,945,969],[4,48,57]],t.SmpRemap={119893:8462,119965:8492,119968:8496,119969:8497,119971:8459,119972:8464,119975:8466,119976:8499,119981:8475,119994:8495,119996:8458,120004:8500,120070:8493,120075:8460,120076:8465,120085:8476,120093:8488,120122:8450,120127:8461,120133:8469,120135:8473,120136:8474,120137:8477,120145:8484},t.SmpRemapGreekU={8711:25,1012:17},t.SmpRemapGreekL={977:27,981:29,982:31,1008:28,1009:30,1013:26,8706:25},t.defaultAccentMap={768:"\u02cb",769:"\u02ca",770:"\u02c6",771:"\u02dc",772:"\u02c9",774:"\u02d8",775:"\u02d9",776:"\xa8",778:"\u02da",780:"\u02c7",8594:"\u20d7",8242:"'",8243:"''",8244:"'''",8245:"`",8246:"``",8247:"```",8279:"''''",8400:"\u21bc",8401:"\u21c0",8406:"\u2190",8417:"\u2194",8432:"*",8411:"...",8412:"....",8428:"\u21c1",8429:"\u21bd",8430:"\u2190",8431:"\u2192"},t.defaultMoMap={45:"\u2212"},t.defaultMnMap={45:"\u2212"},t.defaultParams={x_height:.442,quad:1,num1:.676,num2:.394,num3:.444,denom1:.686,denom2:.345,sup1:.413,sup2:.363,sup3:.289,sub1:.15,sub2:.247,sup_drop:.386,sub_drop:.05,delim1:2.39,delim2:1,axis_height:.25,rule_thickness:.06,big_op_spacing1:.111,big_op_spacing2:.167,big_op_spacing3:.2,big_op_spacing4:.6,big_op_spacing5:.1,surd_height:.075,scriptspace:.05,nulldelimiterspace:.12,delimiterfactor:901,delimitershortfall:.3,min_rule_thickness:1.25,separation_factor:1.75,extra_ic:.033},t.defaultDelimiters={},t.defaultChars={},t.defaultSizeVariants=[],t.defaultStretchVariants=[],t}();e.FontData=l},5373:function(t,e){var r=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonArrow=e.CommonDiagonalArrow=e.CommonDiagonalStrike=e.CommonBorder2=e.CommonBorder=e.arrowBBox=e.diagonalArrowDef=e.arrowDef=e.arrowBBoxW=e.arrowBBoxHD=e.arrowHead=e.fullBorder=e.fullPadding=e.fullBBox=e.sideNames=e.sideIndex=e.SOLID=e.PADDING=e.THICKNESS=e.ARROWY=e.ARROWDX=e.ARROWX=void 0,e.ARROWX=4,e.ARROWDX=1,e.ARROWY=2,e.THICKNESS=.067,e.PADDING=.2,e.SOLID=e.THICKNESS+"em solid",e.sideIndex={top:0,right:1,bottom:2,left:3},e.sideNames=Object.keys(e.sideIndex),e.fullBBox=function(t){return new Array(4).fill(t.thickness+t.padding)},e.fullPadding=function(t){return new Array(4).fill(t.padding)},e.fullBorder=function(t){return new Array(4).fill(t.thickness)};e.arrowHead=function(t){return Math.max(t.padding,t.thickness*(t.arrowhead.x+t.arrowhead.dx+1))};e.arrowBBoxHD=function(t,e){if(t.childNodes[0]){var r=t.childNodes[0].getBBox(),o=r.h,n=r.d;e[0]=e[2]=Math.max(0,t.thickness*t.arrowhead.y-(o+n)/2)}return e};e.arrowBBoxW=function(t,e){if(t.childNodes[0]){var r=t.childNodes[0].getBBox().w;e[1]=e[3]=Math.max(0,t.thickness*t.arrowhead.y-r/2)}return e},e.arrowDef={up:[-Math.PI/2,!1,!0,"verticalstrike"],down:[Math.PI/2,!1,!0,"verticakstrike"],right:[0,!1,!1,"horizontalstrike"],left:[Math.PI,!1,!1,"horizontalstrike"],updown:[Math.PI/2,!0,!0,"verticalstrike uparrow downarrow"],leftright:[0,!0,!1,"horizontalstrike leftarrow rightarrow"]},e.diagonalArrowDef={updiagonal:[-1,0,!1,"updiagonalstrike northeastarrow"],northeast:[-1,0,!1,"updiagonalstrike updiagonalarrow"],southeast:[1,0,!1,"downdiagonalstrike"],northwest:[1,Math.PI,!1,"downdiagonalstrike"],southwest:[-1,Math.PI,!1,"updiagonalstrike"],northeastsouthwest:[-1,0,!0,"updiagonalstrike northeastarrow updiagonalarrow southwestarrow"],northwestsoutheast:[1,0,!0,"downdiagonalstrike northwestarrow southeastarrow"]},e.arrowBBox={up:function(t){return e.arrowBBoxW(t,[e.arrowHead(t),0,t.padding,0])},down:function(t){return e.arrowBBoxW(t,[t.padding,0,e.arrowHead(t),0])},right:function(t){return e.arrowBBoxHD(t,[0,e.arrowHead(t),0,t.padding])},left:function(t){return e.arrowBBoxHD(t,[0,t.padding,0,e.arrowHead(t)])},updown:function(t){return e.arrowBBoxW(t,[e.arrowHead(t),0,e.arrowHead(t),0])},leftright:function(t){return e.arrowBBoxHD(t,[0,e.arrowHead(t),0,e.arrowHead(t)])}};e.CommonBorder=function(t){return function(r){var o=e.sideIndex[r];return[r,{renderer:t,bbox:function(t){var e=[0,0,0,0];return e[o]=t.thickness+t.padding,e},border:function(t){var e=[0,0,0,0];return e[o]=t.thickness,e}}]}};e.CommonBorder2=function(t){return function(r,o,n){var i=e.sideIndex[o],a=e.sideIndex[n];return[r,{renderer:t,bbox:function(t){var e=t.thickness+t.padding,r=[0,0,0,0];return r[i]=r[a]=e,r},border:function(t){var e=[0,0,0,0];return e[i]=e[a]=t.thickness,e},remove:o+" "+n}]}};e.CommonDiagonalStrike=function(t){return function(r){var o="mjx-"+r.charAt(0)+"strike";return[r+"diagonalstrike",{renderer:t(o),bbox:e.fullBBox}]}};e.CommonDiagonalArrow=function(t){return function(o){var n=r(e.diagonalArrowDef[o],4),i=n[0],a=n[1],s=n[2];return[o+"arrow",{renderer:function(e,o){var n=r(e.arrowAW(),2),l=n[0],h=n[1],c=e.arrow(h,i*(l-a),s);t(e,c)},bbox:function(t){var e=t.arrowData(),o=e.a,n=e.x,i=e.y,a=r([t.arrowhead.x,t.arrowhead.y,t.arrowhead.dx],3),s=a[0],l=a[1],h=a[2],c=r(t.getArgMod(s+h,l),2),u=c[0],p=c[1],d=i+(u>o?t.thickness*p*Math.sin(u-o):0),f=n+(u>Math.PI/2-o?t.thickness*p*Math.sin(u+o-Math.PI/2):0);return[d,f,d,f]},remove:n[3]}]}};e.CommonArrow=function(t){return function(o){var n=r(e.arrowDef[o],4),i=n[0],a=n[1],s=n[2],l=n[3];return[o+"arrow",{renderer:function(e,o){var n=e.getBBox(),l=n.w,h=n.h,c=n.d,u=r(s?[h+c,"X"]:[l,"Y"],2),p=u[0],d=u[1],f=e.getOffset(d),m=e.arrow(p,i,a,d,f);t(e,m)},bbox:e.arrowBBox[o],remove:l}]}}},716:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__assign||function(){return(i=Object.assign||function(t){for(var e,r=1,o=arguments.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},s=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonOutputJax=void 0;var l=r(3985),h=r(4769),c=r(9077),u=r(6914),p=r(5878),d=r(5888),f=function(t){function e(e,r,o){void 0===e&&(e=null),void 0===r&&(r=null),void 0===o&&(o=null);var n=this,i=a(c.separateOptions(e,o.OPTIONS),2),s=i[0],l=i[1];return(n=t.call(this,s)||this).factory=n.options.wrapperFactory||new r,n.factory.jax=n,n.cssStyles=n.options.cssStyles||new d.CssStyles,n.font=n.options.font||new o(l),n.unknownCache=new Map,n}return n(e,t),e.prototype.typeset=function(t,e){this.setDocument(e);var r=this.createNode();return this.toDOM(t,r,e),r},e.prototype.createNode=function(){var t=this.constructor.NAME;return this.html("mjx-container",{class:"MathJax",jax:t})},e.prototype.setScale=function(t){var e=this.math.metrics.scale*this.options.scale;1!==e&&this.adaptor.setStyle(t,"fontSize",u.percent(e))},e.prototype.toDOM=function(t,e,r){void 0===r&&(r=null),this.setDocument(r),this.math=t,this.pxPerEm=t.metrics.ex/this.font.params.x_height,t.root.setTeXclass(null),this.setScale(e),this.nodeMap=new Map,this.container=e,this.processMath(t.root,e),this.nodeMap=null,this.executeFilters(this.postFilters,t,r,e)},e.prototype.getBBox=function(t,e){this.setDocument(e),this.math=t,t.root.setTeXclass(null),this.nodeMap=new Map;var r=this.factory.wrap(t.root).getBBox();return this.nodeMap=null,r},e.prototype.getMetrics=function(t){var e,r;this.setDocument(t);var o=this.adaptor,n=this.getMetricMaps(t);try{for(var i=s(t.math),a=i.next();!a.done;a=i.next()){var l=a.value,c=o.parent(l.start.node);if(l.state()=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},a=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},s=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r600?"bold":"normal"),o.family?r=this.explicitVariant(o.family,o.weight,o.style):(this.node.getProperty("variantForm")&&(r="-tex-variant"),r=(e.BOLDVARIANTS[o.weight]||{})[r]||r,r=(e.ITALICVARIANTS[o.style]||{})[r]||r)}this.variant=r}},e.prototype.explicitVariant=function(t,e,r){var o=this.styles;return o||(o=this.styles=new p.Styles),o.set("fontFamily",t),e&&o.set("fontWeight",e),r&&o.set("fontStyle",r),"-explicitFont"},e.prototype.getScale=function(){var t=1,e=this.parent,r=e?e.bbox.scale:1,o=this.node.attributes,n=Math.min(o.get("scriptlevel"),2),i=o.get("fontsize"),a=this.node.isToken||this.node.isKind("mstyle")?o.get("mathsize"):o.getInherited("mathsize");if(0!==n){t=Math.pow(o.get("scriptsizemultiplier"),n);var s=this.length2em(o.get("scriptminsize"),.8,1);t0;this.bbox.L=o.isSet("lspace")?Math.max(0,this.length2em(o.get("lspace"))):y(n,t.lspace),this.bbox.R=o.isSet("rspace")?Math.max(0,this.length2em(o.get("rspace"))):y(n,t.rspace);var i=r.childIndex(e);if(0!==i){var a=r.childNodes[i-1];if(a.isEmbellished){var s=this.jax.nodeMap.get(a).getBBox();s.R&&(this.bbox.L=Math.max(0,this.bbox.L-s.R))}}}},e.prototype.getTeXSpacing=function(t,e){if(!e){var r=this.node.texSpacing();r&&(this.bbox.L=this.length2em(r))}if(t||e){var o=this.node.coreMO().attributes;o.isSet("lspace")&&(this.bbox.L=Math.max(0,this.length2em(o.get("lspace")))),o.isSet("rspace")&&(this.bbox.R=Math.max(0,this.length2em(o.get("rspace"))))}},e.prototype.isTopEmbellished=function(){return this.node.isEmbellished&&!(this.node.parent&&this.node.parent.isEmbellished)},e.prototype.core=function(){return this.jax.nodeMap.get(this.node.core())},e.prototype.coreMO=function(){return this.jax.nodeMap.get(this.node.coreMO())},e.prototype.getText=function(){var t,e,r="";if(this.node.isToken)try{for(var o=i(this.node.childNodes),n=o.next();!n.done;n=o.next()){var a=n.value;a instanceof h.TextNode&&(r+=a.getText())}}catch(e){t={error:e}}finally{try{n&&!n.done&&(e=o.return)&&e.call(o)}finally{if(t)throw t.error}}return r},e.prototype.canStretch=function(t){if(this.stretch=f.NOSTRETCH,this.node.isEmbellished){var e=this.core();e&&e.node!==this.node&&e.canStretch(t)&&(this.stretch=e.stretch)}return 0!==this.stretch.dir},e.prototype.getAlignShift=function(){var t,e=(t=this.node.attributes).getList.apply(t,s([],a(h.indentAttributes))),r=e.indentalign,o=e.indentshift,n=e.indentalignfirst,i=e.indentshiftfirst;return"indentalign"!==n&&(r=n),"auto"===r&&(r=this.jax.options.displayAlign),"indentshift"!==i&&(o=i),"auto"===o&&(o=this.jax.options.displayIndent,"right"!==r||o.match(/^\s*0[a-z]*\s*$/)||(o=("-"+o.trim()).replace(/^--/,""))),[r,this.length2em(o,this.metrics.containerWidth)]},e.prototype.getAlignX=function(t,e,r){return"right"===r?t-(e.w+e.R)*e.rscale:"left"===r?e.L*e.rscale:(t-e.w*e.rscale)/2},e.prototype.getAlignY=function(t,e,r,o,n){return"top"===n?t-r:"bottom"===n?o-e:"center"===n?(t-r-(e-o))/2:0},e.prototype.getWrapWidth=function(t){return this.childNodes[t].getBBox().w},e.prototype.getChildAlign=function(t){return"left"},e.prototype.percent=function(t){return u.percent(t)},e.prototype.em=function(t){return u.em(t)},e.prototype.px=function(t,e){return void 0===e&&(e=-u.BIGDIMEN),u.px(t,e,this.metrics.em)},e.prototype.length2em=function(t,e,r){return void 0===e&&(e=1),void 0===r&&(r=null),null===r&&(r=this.bbox.scale),u.length2em(t,e,r,this.jax.pxPerEm)},e.prototype.unicodeChars=function(t,e){void 0===e&&(e=this.variant);var r=c.unicodeChars(t),o=this.font.getVariant(e);if(o&&o.chars){var n=o.chars;r=r.map((function(t){return((n[t]||[])[3]||{}).smp||t}))}return r},e.prototype.remapChars=function(t){return t},e.prototype.mmlText=function(t){return this.node.factory.create("text").setText(t)},e.prototype.mmlNode=function(t,e,r){return void 0===e&&(e={}),void 0===r&&(r=[]),this.node.factory.create(t,e,r)},e.prototype.createMo=function(t){var e=this.node.factory,r=e.create("text").setText(t),o=e.create("mo",{stretchy:!0},[r]);o.inheritAttributesFrom(this.node);var n=this.wrap(o);return n.parent=this,n},e.prototype.getVariantChar=function(t,e){var r=this.font.getChar(t,e)||[0,0,0,{unknown:!0}];return 3===r.length&&(r[3]={}),r},e.kind="unknown",e.styles={},e.removeStyles=["fontSize","fontFamily","fontWeight","fontStyle","fontVariant","font"],e.skipAttributes={fontfamily:!0,fontsize:!0,fontweight:!0,fontstyle:!0,color:!0,background:!0,class:!0,href:!0,style:!0,xmlns:!0},e.BOLDVARIANTS={bold:{normal:"bold",italic:"bold-italic",fraktur:"bold-fraktur",script:"bold-script","sans-serif":"bold-sans-serif","sans-serif-italic":"sans-serif-bold-italic"},normal:{bold:"normal","bold-italic":"italic","bold-fraktur":"fraktur","bold-script":"script","bold-sans-serif":"sans-serif","sans-serif-bold-italic":"sans-serif-italic"}},e.ITALICVARIANTS={italic:{normal:"italic",bold:"bold-italic","sans-serif":"sans-serif-italic","bold-sans-serif":"sans-serif-bold-italic"},normal:{italic:"normal","bold-italic":"bold","sans-serif-italic":"sans-serif","sans-serif-bold-italic":"bold-sans-serif"}},e}(l.AbstractWrapper);e.CommonWrapper=v},1475:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonWrapperFactory=void 0;var i=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.jax=null,e}return n(e,t),Object.defineProperty(e.prototype,"Wrappers",{get:function(){return this.node},enumerable:!1,configurable:!0}),e.defaultNodes={},e}(r(2506).AbstractWrapperFactory);e.CommonWrapperFactory=i},3438:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonTeXAtomMixin=void 0;var i=r(8921);e.CommonTeXAtomMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.computeBBox=function(e,r){if(void 0===r&&(r=!1),t.prototype.computeBBox.call(this,e,r),this.childNodes[0]&&this.childNodes[0].bbox.ic&&(e.ic=this.childNodes[0].bbox.ic),this.node.texClass===i.TEXCLASS.VCENTER){var o=e.h,n=(o+e.d)/2+this.font.params.axis_height-o;e.h+=n,e.d-=n}},e}(t)}},555:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonTextNodeMixin=void 0,e.CommonTextNodeMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.computeBBox=function(t,e){var r,o;void 0===e&&(e=!1);var a=this.parent.variant,s=this.node.getText();if("-explicitFont"===a){var l=this.jax.getFontData(this.parent.styles),h=this.jax.measureText(s,a,l),c=h.w,u=h.h,p=h.d;t.h=u,t.d=p,t.w=c}else{var d=this.remappedText(s,a);t.empty();try{for(var f=n(d),m=f.next();!m.done;m=f.next()){var y=m.value,v=i(this.getVariantChar(a,y),4),b=(u=v[0],p=v[1],c=v[2],v[3]);if(b.unknown){var x=this.jax.measureText(String.fromCodePoint(y),a);c=x.w,u=x.h,p=x.d}t.w+=c,u>t.h&&(t.h=u),p>t.d&&(t.d=p),t.ic=b.ic||0,t.sk=b.sk||0}}catch(t){r={error:t}}finally{try{m&&!m.done&&(o=f.return)&&o.call(f)}finally{if(r)throw r.error}}d.length>1&&(t.sk=0),t.clean()}},e.prototype.remappedText=function(t,e){var r=this.parent.stretch.c;return r?[r]:this.parent.remapChars(this.unicodeChars(t,e))},e.prototype.getStyles=function(){},e.prototype.getVariant=function(){},e.prototype.getScale=function(){},e.prototype.getSpace=function(){},e}(t)}},3345:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMencloseMixin=void 0;var l=r(5373),h=r(6720);e.CommonMencloseMixin=function(t){return function(t){function e(){for(var e=[],r=0;r.001?s:0},e.prototype.getArgMod=function(t,e){return[Math.atan2(e,t),Math.sqrt(t*t+e*e)]},e.prototype.arrow=function(t,e,r,o,n){return void 0===o&&(o=""),void 0===n&&(n=0),null},e.prototype.arrowData=function(){var t=i([this.padding,this.thickness],2),e=t[0],r=t[1]*(this.arrowhead.x+Math.max(1,this.arrowhead.dx)),o=this.childNodes[0].getBBox(),n=o.h,a=o.d,s=o.w,l=n+a,h=Math.sqrt(l*l+s*s),c=Math.max(e,r*s/h),u=Math.max(e,r*l/h),p=i(this.getArgMod(s+2*c,l+2*u),2);return{a:p[0],W:p[1],x:c,y:u}},e.prototype.arrowAW=function(){var t=this.childNodes[0].getBBox(),e=t.h,r=t.d,o=t.w,n=i(this.TRBL,4),a=n[0],s=n[1],l=n[2],h=n[3];return this.getArgMod(h+o+s,a+e+r+l)},e.prototype.createMsqrt=function(t){var e=this.node.factory.create("msqrt");e.inheritAttributesFrom(this.node),e.childNodes[0]=t.node;var r=this.wrap(e);return r.parent=this,r},e.prototype.sqrtTRBL=function(){var t=this.msqrt.getBBox(),e=this.msqrt.childNodes[0].getBBox();return[t.h-e.h,0,t.d-e.d,t.w-e.w]},e}(t)}},1346:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMfencedMixin=void 0,e.CommonMfencedMixin=function(t){return function(t){function e(){for(var e=[],r=0;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMmultiscriptsMixin=e.ScriptNames=e.NextScript=void 0;var l=r(3717);e.NextScript={base:"subList",subList:"supList",supList:"subList",psubList:"psupList",psupList:"psubList"},e.ScriptNames=["sup","sup","psup","psub"],e.CommonMmultiscriptsMixin=function(t){return function(t){function r(){for(var e=[],r=0;re.length&&e.push(l.BBox.empty())},r.prototype.combineBBoxLists=function(t,e,r,o){for(var n=0;nt.h&&(t.h=l),h>t.d&&(t.d=h),p>e.h&&(e.h=p),d>e.d&&(e.d=d)}},r.prototype.getScaledWHD=function(t){var e=t.w,r=t.h,o=t.d,n=t.rscale;return[e*n,r*n,o*n]},r.prototype.getUVQ=function(e,r){var o;if(!this.UVQ){var n=i([0,0,0],3),a=n[0],s=n[1],l=n[2];0===e.h&&0===e.d?a=this.getU():0===r.h&&0===r.d?a=-this.getV():(a=(o=i(t.prototype.getUVQ.call(this,e,r),3))[0],s=o[1],l=o[2]),this.UVQ=[a,s,l]}return this.UVQ},r}(t)}},2304:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMnMixin=void 0,e.CommonMnMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.remapChars=function(t){if(t.length){var e=this.font.getRemappedChar("mn",t[0]);if(e){var r=this.unicodeChars(e,this.variant);1===r.length?t[0]=r[0]:t=r.concat(t.slice(1))}}return t},e}(t)}},437:function(t,e,r){var o,n,i=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),a=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},s=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMoMixin=e.DirectionVH=void 0;var h=r(3717),c=r(6720),u=r(9250);e.DirectionVH=((n={})[1]="v",n[2]="h",n),e.CommonMoMixin=function(t){return function(t){function e(){for(var e=[],r=0;r=0)&&(t.w=0)},e.prototype.protoBBox=function(e){var r=0!==this.stretch.dir;r&&null===this.size&&this.getStretchedVariant([0]),r&&this.size<0||(t.prototype.computeBBox.call(this,e),this.copySkewIC(e))},e.prototype.getAccentOffset=function(){var t=h.BBox.empty();return this.protoBBox(t),-t.w/2},e.prototype.getCenterOffset=function(e){return void 0===e&&(e=null),e||(e=h.BBox.empty(),t.prototype.computeBBox.call(this,e)),(e.h+e.d)/2+this.font.params.axis_height-e.h},e.prototype.getVariant=function(){this.node.attributes.get("largeop")?this.variant=this.node.attributes.get("displaystyle")?"-largeop":"-smallop":this.node.attributes.getExplicit("mathvariant")||!1!==this.node.getProperty("pseudoscript")?t.prototype.getVariant.call(this):this.variant="-tex-variant"},e.prototype.canStretch=function(t){if(0!==this.stretch.dir)return this.stretch.dir===t;if(!this.node.attributes.get("stretchy"))return!1;var e=this.getText();if(1!==Array.from(e).length)return!1;var r=this.font.getDelimiter(e.codePointAt(0));return this.stretch=r&&r.dir===t?r:u.NOSTRETCH,0!==this.stretch.dir},e.prototype.getStretchedVariant=function(t,e){var r,o;if(void 0===e&&(e=!1),0!==this.stretch.dir){var n=this.getWH(t),i=this.getSize("minsize",0),a=this.getSize("maxsize",1/0),s=this.node.getProperty("mathaccent");n=Math.max(i,Math.min(a,n));var h=this.font.params.delimiterfactor/1e3,c=this.font.params.delimitershortfall,u=i||e?n:s?Math.min(n/h,n+c):Math.max(n*h,n-c),p=this.stretch,d=p.c||this.getText().codePointAt(0),f=0;if(p.sizes)try{for(var m=l(p.sizes),y=m.next();!y.done;y=m.next()){if(y.value>=u)return s&&f&&f--,this.variant=this.font.getSizeVariant(d,f),this.size=f,void(p.schar&&p.schar[f]&&(this.stretch.c=p.schar[f]));f++}}catch(t){r={error:t}}finally{try{y&&!y.done&&(o=m.return)&&o.call(m)}finally{if(r)throw r.error}}p.stretch?(this.size=-1,this.invalidateBBox(),this.getStretchBBox(t,this.checkExtendedHeight(n,p),p)):(this.variant=this.font.getSizeVariant(d,f-1),this.size=f-1)}},e.prototype.getSize=function(t,e){var r=this.node.attributes;return r.isSet(t)&&(e=this.length2em(r.get(t),1,1)),e},e.prototype.getWH=function(t){if(0===t.length)return 0;if(1===t.length)return t[0];var e=a(t,2),r=e[0],o=e[1],n=this.font.params.axis_height;return this.node.attributes.get("symmetric")?2*Math.max(r-n,o+n):r+o},e.prototype.getStretchBBox=function(t,e,r){var o;r.hasOwnProperty("min")&&r.min>e&&(e=r.min);var n=a(r.HDW,3),i=n[0],s=n[1],l=n[2];1===this.stretch.dir?(i=(o=a(this.getBaseline(t,e,r),2))[0],s=o[1]):l=e,this.bbox.h=i,this.bbox.d=s,this.bbox.w=l},e.prototype.getBaseline=function(t,e,r){var o=2===t.length&&t[0]+t[1]===e,n=this.node.attributes.get("symmetric"),i=a(o?t:[e,0],2),s=i[0],l=i[1],h=a([s+l,0],2),c=h[0],u=h[1];if(n){var p=this.font.params.axis_height;o&&(c=2*Math.max(s-p,l+p)),u=c/2-p}else if(o)u=l;else{var d=a(r.HDW||[.75,.25],2),f=d[0],m=d[1];u=m*(c/(f+m))}return[c-u,u]},e.prototype.checkExtendedHeight=function(t,e){if(e.fullExt){var r=a(e.fullExt,2),o=r[0],n=r[1];t=n+Math.ceil(Math.max(0,t-n)/o)*o}return t},e.prototype.remapChars=function(t){var e=this.node.getProperty("primes");if(e)return c.unicodeChars(e);if(1===t.length){var r=this.node.coreParent().parent,o=this.isAccent&&!r.isKind("mrow")?"accent":"mo",n=this.font.getRemappedChar(o,t[0]);n&&(t=this.unicodeChars(n,this.variant))}return t},e}(t)}},7481:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMpaddedMixin=void 0,e.CommonMpaddedMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.getDimens=function(){var t=this.node.attributes.getList("width","height","depth","lspace","voffset"),e=this.childNodes[0].getBBox(),r=e.w,o=e.h,n=e.d,i=r,a=o,s=n,l=0,h=0,c=0;""!==t.width&&(r=this.dimen(t.width,e,"w",0)),""!==t.height&&(o=this.dimen(t.height,e,"h",0)),""!==t.depth&&(n=this.dimen(t.depth,e,"d",0)),""!==t.voffset&&(h=this.dimen(t.voffset,e)),""!==t.lspace&&(l=this.dimen(t.lspace,e));var u=this.node.attributes.get("data-align");return u&&(c=this.getAlignX(r,e,u)),[a,s,i,o-a,n-s,r-i,l,h,c]},e.prototype.dimen=function(t,e,r,o){void 0===r&&(r=""),void 0===o&&(o=null);var n=(t=String(t)).match(/width|height|depth/),i=n?e[n[0].charAt(0)]:r?e[r]:0,a=this.length2em(t,i)||0;return t.match(/^[-+]/)&&r&&(a+=i),null!=o&&(a=Math.max(o,a)),a},e.prototype.computeBBox=function(t,e){void 0===e&&(e=!1);var r=n(this.getDimens(),6),o=r[0],i=r[1],a=r[2],s=r[3],l=r[4],h=r[5];t.w=a+h,t.h=o+s,t.d=i+l,this.setChildPWidths(e,t.w)},e.prototype.getWrapWidth=function(t){return this.getBBox().w},e.prototype.getChildAlign=function(t){return this.node.attributes.get("data-align")||"left"},e}(t)}},5997:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMrootMixin=void 0,e.CommonMrootMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"surd",{get:function(){return 2},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"root",{get:function(){return 1},enumerable:!1,configurable:!0}),e.prototype.combineRootBBox=function(t,e,r){var o=this.childNodes[this.root].getBBox(),n=this.getRootDimens(e,r)[1];t.combine(o,0,n)},e.prototype.getRootDimens=function(t,e){var r=this.childNodes[this.surd],o=this.childNodes[this.root].getBBox(),n=(r.size<0?.5:.6)*t.w,i=o.w,a=o.rscale,s=Math.max(i,n/a),l=Math.max(0,s-i);return[s*a-n,this.rootHeight(o,t,r.size,e),l]},e.prototype.rootHeight=function(t,e,r,o){var n=e.h+e.d;return(r<0?1.9:.55*n)-(n-o)+Math.max(0,t.d*t.rscale)},e}(t)}},9323:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonInferredMrowMixin=e.CommonMrowMixin=void 0;var l=r(3717);e.CommonMrowMixin=function(t){return function(t){function e(){for(var e,r,o=[],n=0;n1){var p=0,d=0,f=c>1&&c===u;try{for(var m=s(this.childNodes),y=m.next();!y.done;y=m.next()){var v=0===(C=y.value).stretch.dir;if(f||v){var b=C.getBBox(v),x=b.h,g=b.d,M=b.rscale;(x*=M)>p&&(p=x),(g*=M)>d&&(d=g)}}}catch(t){r={error:t}}finally{try{y&&!y.done&&(o=m.return)&&o.call(m)}finally{if(r)throw r.error}}try{for(var _=s(a),w=_.next();!w.done;w=_.next()){var C;(C=w.value).coreMO().getStretchedVariant([p,d])}}catch(t){n={error:t}}finally{try{w&&!w.done&&(i=_.return)&&i.call(_)}finally{if(n)throw n.error}}}},e}(t)},e.CommonInferredMrowMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getScale=function(){this.bbox.scale=this.parent.bbox.scale,this.bbox.rscale=1},e}(t)}},6920:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;rthis.surdH?(t.h+t.d-(this.surdH-2*e-r/2))/2:e+r/4]},e.prototype.getRootDimens=function(t,e){return[0,0,0,0]},e}(t)}},3069:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMsubsupMixin=e.CommonMsupMixin=e.CommonMsubMixin=void 0,e.CommonMsubMixin=function(t){var e;return(e=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"scriptChild",{get:function(){return this.childNodes[this.node.sub]},enumerable:!1,configurable:!0}),e.prototype.getOffset=function(){return[0,-this.getV()]},e}(t)).useIC=!1,e},e.CommonMsupMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"scriptChild",{get:function(){return this.childNodes[this.node.sup]},enumerable:!1,configurable:!0}),e.prototype.getOffset=function(){return[this.getAdjustedIc()-(this.baseRemoveIc?0:this.baseIc),this.getU()]},e}(t)},e.CommonMsubsupMixin=function(t){var e;return(e=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.UVQ=null,e}return o(e,t),Object.defineProperty(e.prototype,"subChild",{get:function(){return this.childNodes[this.node.sub]},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"supChild",{get:function(){return this.childNodes[this.node.sup]},enumerable:!1,configurable:!0}),e.prototype.computeBBox=function(t,e){void 0===e&&(e=!1);var r=this.baseChild.getBBox(),o=n([this.subChild.getBBox(),this.supChild.getBBox()],2),i=o[0],a=o[1];t.empty(),t.append(r);var s=this.getBaseWidth(),l=this.getAdjustedIc(),h=n(this.getUVQ(),2),c=h[0],u=h[1];t.combine(i,s,u),t.combine(a,s+l,c),t.w+=this.font.params.scriptspace,t.clean(),this.setChildPWidths(e)},e.prototype.getUVQ=function(t,e){void 0===t&&(t=this.subChild.getBBox()),void 0===e&&(e=this.supChild.getBBox());var r=this.baseCore.getBBox();if(this.UVQ)return this.UVQ;var o=this.font.params,i=3*o.rule_thickness,a=this.length2em(this.node.attributes.get("subscriptshift"),o.sub2),s=this.baseCharZero(r.d*this.baseScale+o.sub_drop*t.rscale),l=n([this.getU(),Math.max(s,a)],2),h=l[0],c=l[1],u=h-e.d*e.rscale-(t.h*t.rscale-c);if(u0&&(h+=p,c-=p)}return h=Math.max(this.length2em(this.node.attributes.get("superscriptshift"),h),h),c=Math.max(this.length2em(this.node.attributes.get("subscriptshift"),c),c),u=h-e.d*e.rscale-(t.h*t.rscale-c),this.UVQ=[h,-c,u],this.UVQ},e}(t)).useIC=!1,e}},8589:function(t,e,r){var o,n=this&&this.__extends||(o=function(t,e){return(o=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])})(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}o(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),i=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},a=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMtableMixin=void 0;var l=r(3717),h=r(6720),c=r(1490);e.CommonMtableMixin=function(t){return function(t){function e(){for(var e=[],r=0;r1){if(null===e){e=0;var f=p>1&&p===d;try{for(var m=s(this.tableRows),y=m.next();!y.done;y=m.next()){var v;if(v=y.value.getChild(t)){var b=0===(_=v.childNodes[0]).stretch.dir;if(f||b){var x=_.getBBox(b).w;x>e&&(e=x)}}}}catch(t){n={error:t}}finally{try{y&&!y.done&&(i=m.return)&&i.call(m)}finally{if(n)throw n.error}}}try{for(var g=s(h),M=g.next();!M.done;M=g.next()){var _;(_=M.value).coreMO().getStretchedVariant([e])}}catch(t){a={error:t}}finally{try{M&&!M.done&&(l=g.return)&&l.call(g)}finally{if(a)throw a.error}}}},e.prototype.getTableData=function(){if(this.data)return this.data;for(var t=new Array(this.numRows).fill(0),e=new Array(this.numRows).fill(0),r=new Array(this.numCols).fill(0),o=new Array(this.numRows),n=new Array(this.numRows),i=[0],a=this.tableRows,s=0;sn[r]&&(n[r]=h),c>i[r]&&(i[r]=c),d>s&&(s=d),a&&u>a[e]&&(a[e]=u),s},e.prototype.extendHD=function(t,e,r,o){var n=(o-(e[t]+r[t]))/2;n<1e-5||(e[t]+=n,r[t]+=n)},e.prototype.recordPWidthCell=function(t,e){t.childNodes[0]&&t.childNodes[0].getBBox().pwidth&&this.pwidthCells.push([t,e])},e.prototype.computeBBox=function(t,e){void 0===e&&(e=!1);var r,o,n=this.getTableData(),a=n.H,s=n.D;if(this.node.attributes.get("equalrows")){var l=this.getEqualRowHeight();r=c.sum([].concat(this.rLines,this.rSpace))+l*this.numRows}else r=c.sum(a.concat(s,this.rLines,this.rSpace));r+=2*(this.fLine+this.fSpace[1]);var u=this.getComputedWidths();o=c.sum(u.concat(this.cLines,this.cSpace))+2*(this.fLine+this.fSpace[0]);var p=this.node.attributes.get("width");"auto"!==p&&(o=Math.max(this.length2em(p,0)+2*this.fLine,o));var d=i(this.getBBoxHD(r),2),f=d[0],m=d[1];t.h=f,t.d=m,t.w=o;var y=i(this.getBBoxLR(),2),v=y[0],b=y[1];t.L=v,t.R=b,h.isPercent(p)||this.setColumnPWidths()},e.prototype.setChildPWidths=function(t,e,r){var o=this.node.attributes.get("width");if(!h.isPercent(o))return!1;this.hasLabels||(this.bbox.pwidth="",this.container.bbox.pwidth="");var n=this.bbox,i=n.w,a=n.L,s=n.R,l=Math.max(i,this.length2em(o,Math.max(e,a+i+s))),u=this.node.attributes.get("equalcolumns")?Array(this.numCols).fill(this.percent(1/Math.max(1,this.numCols))):this.getColumnAttributes("columnwidth",0);this.cWidths=this.getColumnWidthsFixed(u,l);var p=this.getComputedWidths();return this.pWidth=c.sum(p.concat(this.cLines,this.cSpace))+2*(this.fLine+this.fSpace[0]),this.isTop&&(this.bbox.w=this.pWidth),this.setColumnPWidths(),this.pWidth!==i&&this.parent.invalidateBBox(),this.pWidth!==i},e.prototype.setColumnPWidths=function(){var t,e,r=this.cWidths;try{for(var o=s(this.pwidthCells),n=o.next();!n.done;n=o.next()){var a=i(n.value,2),l=a[0],h=a[1];l.setChildPWidths(!1,r[h])&&(l.invalidateBBox(),l.getBBox())}}catch(e){t={error:e}}finally{try{n&&!n.done&&(e=o.return)&&e.call(o)}finally{if(t)throw t.error}}},e.prototype.getBBoxHD=function(t){var e=i(this.getAlignmentRow(),2),r=e[0],o=e[1];if(null===o){var n=this.font.params.axis_height,a=t/2;return{top:[0,t],center:[a,a],bottom:[t,0],baseline:[a,a],axis:[a+n,a-n]}[r]||[a,a]}var s=this.getVerticalPosition(o,r);return[s,t-s]},e.prototype.getBBoxLR=function(){if(this.hasLabels){var t=this.node.attributes.get("side"),e=i(this.getPadAlignShift(t),2),r=e[0];return"center"===e[1]?[r,r]:"left"===t?[r,0]:[0,r]}return[0,0]},e.prototype.getPadAlignShift=function(t){var e=this.getTableData().L+this.length2em(this.node.attributes.get("minlabelspacing")),r=i(null==this.styles?["",""]:[this.styles.get("padding-left"),this.styles.get("padding-right")],2),o=r[0],n=r[1];(o||n)&&(e=Math.max(e,this.length2em(o||"0"),this.length2em(n||"0")));var a=i(this.getAlignShift(),2),s=a[0],l=a[1];return s===t&&(l="left"===t?Math.max(e,l)-e:Math.min(-e,l)+e),[e,s,l]},e.prototype.getAlignShift=function(){return this.isTop?t.prototype.getAlignShift.call(this):[this.container.getChildAlign(this.containerI),0]},e.prototype.getWidth=function(){return this.pWidth||this.getBBox().w},e.prototype.getEqualRowHeight=function(){var t=this.getTableData(),e=t.H,r=t.D,o=Array.from(e.keys()).map((function(t){return e[t]+r[t]}));return Math.max.apply(Math,o)},e.prototype.getComputedWidths=function(){var t=this,e=this.getTableData().W,r=Array.from(e.keys()).map((function(r){return"number"==typeof t.cWidths[r]?t.cWidths[r]:e[r]}));return this.node.attributes.get("equalcolumns")&&(r=Array(r.length).fill(c.max(r))),r},e.prototype.getColumnWidths=function(){var t=this.node.attributes.get("width");if(this.node.attributes.get("equalcolumns"))return this.getEqualColumns(t);var e=this.getColumnAttributes("columnwidth",0);return"auto"===t?this.getColumnWidthsAuto(e):h.isPercent(t)?this.getColumnWidthsPercent(e):this.getColumnWidthsFixed(e,this.length2em(t))},e.prototype.getEqualColumns=function(t){var e,r=Math.max(1,this.numCols);if("auto"===t){var o=this.getTableData().W;e=c.max(o)}else if(h.isPercent(t))e=this.percent(1/r);else{var n=c.sum([].concat(this.cLines,this.cSpace))+2*this.fSpace[0];e=Math.max(0,this.length2em(t)-n)/r}return Array(this.numCols).fill(e)},e.prototype.getColumnWidthsAuto=function(t){var e=this;return t.map((function(t){return"auto"===t||"fit"===t?null:h.isPercent(t)?t:e.length2em(t)}))},e.prototype.getColumnWidthsPercent=function(t){var e=this,r=t.indexOf("fit")>=0,o=(r?this.getTableData():{W:null}).W;return Array.from(t.keys()).map((function(n){var i=t[n];return"fit"===i?null:"auto"===i?r?o[n]:null:h.isPercent(i)?i:e.length2em(i)}))},e.prototype.getColumnWidthsFixed=function(t,e){var r=this,o=Array.from(t.keys()),n=o.filter((function(e){return"fit"===t[e]})),i=o.filter((function(e){return"auto"===t[e]})),a=n.length||i.length,s=(a?this.getTableData():{W:null}).W,l=e-c.sum([].concat(this.cLines,this.cSpace))-2*this.fSpace[0],h=l;o.forEach((function(o){var n=t[o];h-="fit"===n||"auto"===n?s[o]:r.length2em(n,e)}));var u=a&&h>0?h/a:0;return o.map((function(e){var o=t[e];return"fit"===o?s[e]+u:"auto"===o?s[e]+(0===n.length?u:0):r.length2em(o,l)}))},e.prototype.getVerticalPosition=function(t,e){for(var r=this.node.attributes.get("equalrows"),o=this.getTableData(),n=o.H,a=o.D,s=r?this.getEqualRowHeight():0,l=this.getRowHalfSpacing(),h=this.fLine,c=0;cthis.numRows?null:o-1]},e.prototype.getColumnAttributes=function(t,e){void 0===e&&(e=1);var r=this.numCols-e,o=this.getAttributeArray(t);if(0===o.length)return null;for(;o.lengthr&&o.splice(r),o},e.prototype.getRowAttributes=function(t,e){void 0===e&&(e=1);var r=this.numRows-e,o=this.getAttributeArray(t);if(0===o.length)return null;for(;o.lengthr&&o.splice(r),o},e.prototype.getAttributeArray=function(t){var e=this.node.attributes.get(t);return e?h.split(e):[this.node.attributes.getDefault(t)]},e.prototype.addEm=function(t,e){var r=this;return void 0===e&&(e=1),t?t.map((function(t){return r.em(t/e)})):null},e.prototype.convertLengths=function(t){var e=this;return t?t.map((function(t){return e.length2em(t)})):null},e}(t)}},7805:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMtdMixin=void 0,e.CommonMtdMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"fixesPWidth",{get:function(){return!1},enumerable:!1,configurable:!0}),e.prototype.invalidateBBox=function(){this.bboxComputed=!1},e.prototype.getWrapWidth=function(t){var e=this.parent.parent,r=this.parent,o=this.node.childPosition()-(r.labeled?1:0);return"number"==typeof e.cWidths[o]?e.cWidths[o]:e.getTableData().W[o]},e.prototype.getChildAlign=function(t){return this.node.attributes.get("columnalign")},e}(t)}},8325:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMtextMixin=void 0,e.CommonMtextMixin=function(t){var e;return(e=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.getVariant=function(){var e=this.jax.options,r=this.jax.math.outputData,o=(!!r.merrorFamily||!!e.merrorFont)&&this.node.Parent.isKind("merror");if(r.mtextFamily||e.mtextFont||o){var n=this.node.attributes.get("mathvariant"),i=this.constructor.INHERITFONTS[n]||this.jax.font.getCssFont(n),a=i[0]||(o?r.merrorFamily||e.merrorFont:r.mtextFamily||e.mtextFont);this.variant=this.explicitVariant(a,i[2]?"bold":"",i[1]?"italic":"")}else t.prototype.getVariant.call(this)},e}(t)).INHERITFONTS={normal:["",!1,!1],bold:["",!1,!0],italic:["",!0,!1],"bold-italic":["",!0,!0]},e}},4818:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__values||function(t){var e="function"==typeof Symbol&&Symbol.iterator,r=e&&t[e],o=0;if(r)return r.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&o>=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonMlabeledtrMixin=e.CommonMtrMixin=void 0,e.CommonMtrMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"fixesPWidth",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"numCells",{get:function(){return this.childNodes.length},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"labeled",{get:function(){return!1},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"tableCells",{get:function(){return this.childNodes},enumerable:!1,configurable:!0}),e.prototype.getChild=function(t){return this.childNodes[t]},e.prototype.getChildBBoxes=function(){return this.childNodes.map((function(t){return t.getBBox()}))},e.prototype.stretchChildren=function(t){var e,r,o,i,a,s;void 0===t&&(t=null);var l=[],h=this.labeled?this.childNodes.slice(1):this.childNodes;try{for(var c=n(h),u=c.next();!u.done;u=c.next()){(j=u.value.childNodes[0]).canStretch(1)&&l.push(j)}}catch(t){e={error:t}}finally{try{u&&!u.done&&(r=c.return)&&r.call(c)}finally{if(e)throw e.error}}var p=l.length,d=this.childNodes.length;if(p&&d>1){if(null===t){var f=0,m=0,y=p>1&&p===d;try{for(var v=n(h),b=v.next();!b.done;b=v.next()){var x=0===(j=b.value.childNodes[0]).stretch.dir;if(y||x){var g=j.getBBox(x),M=g.h,_=g.d;M>f&&(f=M),_>m&&(m=_)}}}catch(t){o={error:t}}finally{try{b&&!b.done&&(i=v.return)&&i.call(v)}finally{if(o)throw o.error}}t=[f,m]}try{for(var w=n(l),C=w.next();!C.done;C=w.next()){var j;(j=C.value).coreMO().getStretchedVariant(t)}}catch(t){a={error:t}}finally{try{C&&!C.done&&(s=w.return)&&s.call(w)}finally{if(a)throw a.error}}}},e}(t)},e.CommonMlabeledtrMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),Object.defineProperty(e.prototype,"numCells",{get:function(){return Math.max(0,this.childNodes.length-1)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"labeled",{get:function(){return!0},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"tableCells",{get:function(){return this.childNodes.slice(1)},enumerable:!1,configurable:!0}),e.prototype.getChild=function(t){return this.childNodes[t+1]},e.prototype.getChildBBoxes=function(){return this.childNodes.slice(1).map((function(t){return t.getBBox()}))},e}(t)}},9690:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)}),n=this&&this.__read||function(t,e){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var o,n,i=r.call(t),a=[];try{for(;(void 0===e||e-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r0)&&!(o=i.next()).done;)a.push(o.value)}catch(t){n={error:t}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}return a},i=this&&this.__spreadArray||function(t,e){for(var r=0,o=e.length,n=t.length;r=t.length&&(t=void 0),{value:t&&t[o++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(e,"__esModule",{value:!0}),e.CommonScriptbaseMixin=void 0,e.CommonScriptbaseMixin=function(t){var e;return(e=function(t){function e(){for(var e=[],r=0;r1){var p=0,d=c>1&&c===u;try{for(var f=a(this.childNodes),m=f.next();!m.done;m=f.next()){var y=0===(_=m.value).stretch.dir;if(d||y){var v=_.getBBox(y),b=v.w,x=v.rscale;b*x>p&&(p=b*x)}}}catch(t){r={error:t}}finally{try{m&&!m.done&&(o=f.return)&&o.call(f)}finally{if(r)throw r.error}}try{for(var g=a(s),M=g.next();!M.done;M=g.next()){var _;(_=M.value).coreMO().getStretchedVariant([p/_.bbox.rscale])}}catch(t){n={error:t}}finally{try{M&&!M.done&&(i=g.return)&&i.call(g)}finally{if(n)throw n.error}}}},e}(t)).useIC=!0,e}},3191:function(t,e){var r,o=this&&this.__extends||(r=function(t,e){return(r=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])})(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 o(){this.constructor=t}r(t,e),t.prototype=null===e?Object.create(e):(o.prototype=e.prototype,new o)});Object.defineProperty(e,"__esModule",{value:!0}),e.CommonSemanticsMixin=void 0,e.CommonSemanticsMixin=function(t){return function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return o(e,t),e.prototype.computeBBox=function(t,e){if(void 0===e&&(e=!1),this.childNodes.length){var r=this.childNodes[0].getBBox(),o=r.w,n=r.h,i=r.d;t.w=o,t.h=n,t.d=i}},e}(t)}},8723:function(t,e){MathJax._.components.global.isObject,MathJax._.components.global.combineConfig,e.PV=MathJax._.components.global.combineDefaults,e.r8=MathJax._.components.global.combineWithMathJax,MathJax._.components.global.MathJax},4769:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.protoItem=MathJax._.core.MathItem.protoItem,e.AbstractMathItem=MathJax._.core.MathItem.AbstractMathItem,e.STATE=MathJax._.core.MathItem.STATE,e.newState=MathJax._.core.MathItem.newState},8921:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.TEXCLASS=MathJax._.core.MmlTree.MmlNode.TEXCLASS,e.TEXCLASSNAMES=MathJax._.core.MmlTree.MmlNode.TEXCLASSNAMES,e.indentAttributes=MathJax._.core.MmlTree.MmlNode.indentAttributes,e.AbstractMmlNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlNode,e.AbstractMmlTokenNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlTokenNode,e.AbstractMmlLayoutNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlLayoutNode,e.AbstractMmlBaseNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlBaseNode,e.AbstractMmlEmptyNode=MathJax._.core.MmlTree.MmlNode.AbstractMmlEmptyNode,e.TextNode=MathJax._.core.MmlTree.MmlNode.TextNode,e.XMLNode=MathJax._.core.MmlTree.MmlNode.XMLNode},4282:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.TeXAtom=MathJax._.core.MmlTree.MmlNodes.TeXAtom.TeXAtom},3969:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMaction=MathJax._.core.MmlTree.MmlNodes.maction.MmlMaction},304:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMath=MathJax._.core.MmlTree.MmlNodes.math.MmlMath},4374:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMenclose=MathJax._.core.MmlTree.MmlNodes.menclose.MmlMenclose},7451:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMfenced=MathJax._.core.MmlTree.MmlNodes.mfenced.MmlMfenced},848:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMfrac=MathJax._.core.MmlTree.MmlNodes.mfrac.MmlMfrac},910:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMglyph=MathJax._.core.MmlTree.MmlNodes.mglyph.MmlMglyph},7754:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMi=MathJax._.core.MmlTree.MmlNodes.mi.MmlMi},7764:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMmultiscripts=MathJax._.core.MmlTree.MmlNodes.mmultiscripts.MmlMmultiscripts,e.MmlMprescripts=MathJax._.core.MmlTree.MmlNodes.mmultiscripts.MmlMprescripts,e.MmlNone=MathJax._.core.MmlTree.MmlNodes.mmultiscripts.MmlNone},3235:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMn=MathJax._.core.MmlTree.MmlNodes.mn.MmlMn},9946:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMo=MathJax._.core.MmlTree.MmlNodes.mo.MmlMo},189:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMpadded=MathJax._.core.MmlTree.MmlNodes.mpadded.MmlMpadded},4664:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMroot=MathJax._.core.MmlTree.MmlNodes.mroot.MmlMroot},1691:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMrow=MathJax._.core.MmlTree.MmlNodes.mrow.MmlMrow,e.MmlInferredMrow=MathJax._.core.MmlTree.MmlNodes.mrow.MmlInferredMrow},4042:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMs=MathJax._.core.MmlTree.MmlNodes.ms.MmlMs},1465:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMspace=MathJax._.core.MmlTree.MmlNodes.mspace.MmlMspace},4655:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMsqrt=MathJax._.core.MmlTree.MmlNodes.msqrt.MmlMsqrt},5857:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMsubsup=MathJax._.core.MmlTree.MmlNodes.msubsup.MmlMsubsup,e.MmlMsub=MathJax._.core.MmlTree.MmlNodes.msubsup.MmlMsub,e.MmlMsup=MathJax._.core.MmlTree.MmlNodes.msubsup.MmlMsup},4859:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMtable=MathJax._.core.MmlTree.MmlNodes.mtable.MmlMtable},2321:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMtd=MathJax._.core.MmlTree.MmlNodes.mtd.MmlMtd},6277:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMtext=MathJax._.core.MmlTree.MmlNodes.mtext.MmlMtext},4393:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMtr=MathJax._.core.MmlTree.MmlNodes.mtr.MmlMtr,e.MmlMlabeledtr=MathJax._.core.MmlTree.MmlNodes.mtr.MmlMlabeledtr},3102:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlMunderover=MathJax._.core.MmlTree.MmlNodes.munderover.MmlMunderover,e.MmlMunder=MathJax._.core.MmlTree.MmlNodes.munderover.MmlMunder,e.MmlMover=MathJax._.core.MmlTree.MmlNodes.munderover.MmlMover},9167:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.MmlSemantics=MathJax._.core.MmlTree.MmlNodes.semantics.MmlSemantics,e.MmlAnnotationXML=MathJax._.core.MmlTree.MmlNodes.semantics.MmlAnnotationXML,e.MmlAnnotation=MathJax._.core.MmlTree.MmlNodes.semantics.MmlAnnotation},3985:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractOutputJax=MathJax._.core.OutputJax.AbstractOutputJax},9879:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractWrapper=MathJax._.core.Tree.Wrapper.AbstractWrapper},2506:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractWrapperFactory=MathJax._.core.Tree.WrapperFactory.AbstractWrapperFactory},3717:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.BBoxStyleAdjust=MathJax._.util.BBox.BBoxStyleAdjust,e.BBox=MathJax._.util.BBox.BBox},9077:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.APPEND=MathJax._.util.Options.APPEND,e.REMOVE=MathJax._.util.Options.REMOVE,e.Expandable=MathJax._.util.Options.Expandable,e.expandable=MathJax._.util.Options.expandable,e.makeArray=MathJax._.util.Options.makeArray,e.keys=MathJax._.util.Options.keys,e.copy=MathJax._.util.Options.copy,e.insert=MathJax._.util.Options.insert,e.defaultOptions=MathJax._.util.Options.defaultOptions,e.userOptions=MathJax._.util.Options.userOptions,e.selectOptions=MathJax._.util.Options.selectOptions,e.selectOptionsFromKeys=MathJax._.util.Options.selectOptionsFromKeys,e.separateOptions=MathJax._.util.Options.separateOptions},5888:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.CssStyles=MathJax._.util.StyleList.CssStyles},5878:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.Styles=MathJax._.util.Styles.Styles},6914:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.BIGDIMEN=MathJax._.util.lengths.BIGDIMEN,e.UNITS=MathJax._.util.lengths.UNITS,e.RELUNITS=MathJax._.util.lengths.RELUNITS,e.MATHSPACE=MathJax._.util.lengths.MATHSPACE,e.length2em=MathJax._.util.lengths.length2em,e.percent=MathJax._.util.lengths.percent,e.em=MathJax._.util.lengths.em,e.emRounded=MathJax._.util.lengths.emRounded,e.px=MathJax._.util.lengths.px},1490:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.sum=MathJax._.util.numeric.sum,e.max=MathJax._.util.numeric.max},6720:function(t,e){Object.defineProperty(e,"__esModule",{value:!0}),e.sortLength=MathJax._.util.string.sortLength,e.quotePattern=MathJax._.util.string.quotePattern,e.unicodeChars=MathJax._.util.string.unicodeChars,e.unicodeString=MathJax._.util.string.unicodeString,e.isPercent=MathJax._.util.string.isPercent,e.split=MathJax._.util.string.split},4142:function(t,e,r){r.r(e),r.d(e,{TeXFont:function(){return c}});var o=r(2098);function n(t){return(n="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)}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function a(t,e){return(a=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function s(t){var e=function(){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}}();return function(){var r,o=h(t);if(e){var n=h(this).constructor;r=Reflect.construct(o,arguments,n)}else r=o.apply(this,arguments);return l(this,r)}}function l(t,e){return!e||"object"!==n(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function h(t){return(h=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}var c=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&a(t,e)}(r,t);var e=s(r);function r(){return i(this,r),e.apply(this,arguments)}return r}(o.FontData);c.OPTIONS={fontURL:"."}}},ut={};function pt(t){var e=ut[t];if(void 0!==e)return e.exports;var r=ut[t]={exports:{}};return ct[t].call(r.exports,r,r.exports,pt),r.exports}pt.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return pt.d(e,{a:e}),e},pt.d=function(t,e){for(var r in e)pt.o(e,r)&&!pt.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},pt.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},pt.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},t=pt(8723),e=pt(7016),r=pt(2098),o=pt(4458),n=pt(6617),i=pt(4477),a=pt(8369),s=pt(518),l=pt(1114),h=pt(7918),c=pt(4155),u=pt(3215),p=pt(7047),d=pt(7837),f=pt(1315),m=pt(3271),y=pt(1096),v=pt(7013),b=pt(3292),x=pt(7215),g=pt(7111),M=pt(3126),_=pt(9821),w=pt(6024),C=pt(5437),j=pt(513),S=pt(6918),O=pt(8709),T=pt(6359),L=pt(7500),B=pt(6577),P=pt(7322),H=pt(7795),A=pt(9250),k=pt(5373),N=pt(716),E=pt(1541),D=pt(1475),W=pt(3438),R=pt(555),I=pt(3345),F=pt(2057),J=pt(6200),V=pt(1346),z=pt(5705),X=pt(7969),K=pt(1419),q=pt(9906),U=pt(2304),Q=pt(437),G=pt(7481),Y=pt(5997),Z=pt(9323),$=pt(6920),tt=pt(37),et=pt(222),rt=pt(3069),ot=pt(8589),nt=pt(7805),it=pt(8325),at=pt(4818),st=pt(9690),lt=pt(7091),ht=pt(3191),(0,t.r8)({_:{output:{chtml_ts:e,chtml:{FontData:r,Notation:o,Wrapper:n,WrapperFactory:i,Wrappers_ts:a,Wrappers:{TeXAtom:s,TextNode:l,maction:h,math:c,menclose:u,mfenced:p,mfrac:d,mglyph:f,mi:m,mmultiscripts:y,mn:v,mo:b,mpadded:x,mroot:g,mrow:M,ms:_,mspace:w,msqrt:C,msubsup:j,mtable:S,mtd:O,mtext:T,mtr:L,munderover:B,scriptbase:P,semantics:H}},common:{FontData:A,Notation:k,OutputJax:N,Wrapper:E,WrapperFactory:D,Wrappers:{TeXAtom:W,TextNode:R,maction:I,math:F,menclose:J,mfenced:V,mfrac:z,mglyph:X,mi:K,mmultiscripts:q,mn:U,mo:Q,mpadded:G,mroot:Y,mrow:Z,ms:$,mspace:tt,msqrt:et,msubsup:rt,mtable:ot,mtd:nt,mtext:it,mtr:at,munderover:st,scriptbase:lt,semantics:ht}}}}}),MathJax.loader&&(0,t.PV)(MathJax.config.loader,"output/chtml",{checkReady:function(){return MathJax.loader.load("output/chtml/fonts/tex")}}),MathJax.startup&&(MathJax.startup.registerConstructor("chtml",e.CHTML),MathJax.startup.useOutput("chtml"))}(); \ No newline at end of file diff --git a/docs/assets/vendor/mathjax/output/chtml/fonts/tex.js b/docs/assets/vendor/mathjax/output/chtml/fonts/tex.js new file mode 100644 index 0000000..0a7a1fb --- /dev/null +++ b/docs/assets/vendor/mathjax/output/chtml/fonts/tex.js @@ -0,0 +1 @@ +!function(){"use strict";var c={2308:function(c,f,i){var t,e=this&&this.__extends||(t=function(c,f){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(c,f){c.__proto__=f}||function(c,f){for(var i in f)Object.prototype.hasOwnProperty.call(f,i)&&(c[i]=f[i])})(c,f)},function(c,f){if("function"!=typeof f&&null!==f)throw new TypeError("Class extends value "+String(f)+" is not a constructor or null");function i(){this.constructor=c}t(c,f),c.prototype=null===f?Object.create(f):(i.prototype=f.prototype,new i)}),s=this&&this.__assign||function(){return(s=Object.assign||function(c){for(var f,i=1,t=arguments.length;i\\338"},8816:{c:"\\2264\\338"},8817:{c:"\\2265\\338"},8832:{c:"\\227A\\338"},8833:{c:"\\227B\\338"},8836:{c:"\\2282\\338"},8837:{c:"\\2283\\338"},8840:{c:"\\2286\\338"},8841:{c:"\\2287\\338"},8876:{c:"\\22A2\\338"},8877:{c:"\\22A8\\338"},8930:{c:"\\2291\\338"},8931:{c:"\\2292\\338"},9001:{c:"\\27E8"},9002:{c:"\\27E9"},9653:{c:"\\25B3"},9663:{c:"\\25BD"},10072:{c:"\\2223"},10744:{c:"/",f:"BI"},10799:{c:"\\D7"},12296:{c:"\\27E8"},12297:{c:"\\27E9"}})},6051:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.doubleStruck=void 0;var t=i(5674);Object.defineProperty(f,"doubleStruck",{enumerable:!0,get:function(){return t.doubleStruck}})},9236:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.frakturBold=void 0;var t=i(73),e=i(7002);f.frakturBold=t.AddCSS(e.frakturBold,{8260:{c:"/"}})},1937:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.fraktur=void 0;var t=i(73),e=i(9349);f.fraktur=t.AddCSS(e.fraktur,{8260:{c:"/"}})},4244:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.italic=void 0;var t=i(73),e=i(9741);f.italic=t.AddCSS(e.italic,{47:{f:"I"},989:{c:"\\E008",f:"A"},8213:{c:"\\2014"},8215:{c:"_"},8260:{c:"/",f:"I"},8710:{c:"\\394",f:"I"},10744:{c:"/",f:"I"}})},482:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.largeop=void 0;var t=i(73),e=i(2827);f.largeop=t.AddCSS(e.largeop,{8214:{f:"S1"},8260:{c:"/"},8593:{f:"S1"},8595:{f:"S1"},8657:{f:"S1"},8659:{f:"S1"},8739:{f:"S1"},8741:{f:"S1"},9001:{c:"\\27E8"},9002:{c:"\\27E9"},9168:{f:"S1"},10072:{c:"\\2223",f:"S1"},10764:{c:"\\222C\\222C"},12296:{c:"\\27E8"},12297:{c:"\\27E9"}})},196:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.monospace=void 0;var t=i(73),e=i(2970);f.monospace=t.AddCSS(e.monospace,{697:{c:"\\2032"},913:{c:"A"},914:{c:"B"},917:{c:"E"},918:{c:"Z"},919:{c:"H"},921:{c:"I"},922:{c:"K"},924:{c:"M"},925:{c:"N"},927:{c:"O"},929:{c:"P"},932:{c:"T"},935:{c:"X"},8215:{c:"_"},8243:{c:"\\2032\\2032"},8244:{c:"\\2032\\2032\\2032"},8260:{c:"/"},8279:{c:"\\2032\\2032\\2032\\2032"},8710:{c:"\\394"}})},527:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.normal=void 0;var t=i(73),e=i(1668);f.normal=t.AddCSS(e.normal,{163:{f:"MI"},165:{f:"A"},174:{f:"A"},183:{c:"\\22C5"},240:{f:"A"},697:{c:"\\2032"},913:{c:"A"},914:{c:"B"},917:{c:"E"},918:{c:"Z"},919:{c:"H"},921:{c:"I"},922:{c:"K"},924:{c:"M"},925:{c:"N"},927:{c:"O"},929:{c:"P"},932:{c:"T"},935:{c:"X"},8192:{c:""},8193:{c:""},8194:{c:""},8195:{c:""},8196:{c:""},8197:{c:""},8198:{c:""},8201:{c:""},8202:{c:""},8203:{c:""},8204:{c:""},8213:{c:"\\2014"},8214:{c:"\\2225"},8215:{c:"_"},8226:{c:"\\2219"},8243:{c:"\\2032\\2032"},8244:{c:"\\2032\\2032\\2032"},8245:{f:"A"},8246:{c:"\\2035\\2035",f:"A"},8247:{c:"\\2035\\2035\\2035",f:"A"},8254:{c:"\\2C9"},8260:{c:"/"},8279:{c:"\\2032\\2032\\2032\\2032"},8288:{c:""},8289:{c:""},8290:{c:""},8291:{c:""},8292:{c:""},8407:{c:"\\2192",f:"V"},8450:{c:"C",f:"A"},8459:{c:"H",f:"SC"},8460:{c:"H",f:"FR"},8461:{c:"H",f:"A"},8462:{c:"h",f:"I"},8463:{f:"A"},8464:{c:"I",f:"SC"},8465:{c:"I",f:"FR"},8466:{c:"L",f:"SC"},8469:{c:"N",f:"A"},8473:{c:"P",f:"A"},8474:{c:"Q",f:"A"},8475:{c:"R",f:"SC"},8476:{c:"R",f:"FR"},8477:{c:"R",f:"A"},8484:{c:"Z",f:"A"},8486:{c:"\\3A9"},8487:{f:"A"},8488:{c:"Z",f:"FR"},8492:{c:"B",f:"SC"},8493:{c:"C",f:"FR"},8496:{c:"E",f:"SC"},8497:{c:"F",f:"SC"},8498:{f:"A"},8499:{c:"M",f:"SC"},8502:{f:"A"},8503:{f:"A"},8504:{f:"A"},8513:{f:"A"},8602:{f:"A"},8603:{f:"A"},8606:{f:"A"},8608:{f:"A"},8610:{f:"A"},8611:{f:"A"},8619:{f:"A"},8620:{f:"A"},8621:{f:"A"},8622:{f:"A"},8624:{f:"A"},8625:{f:"A"},8630:{f:"A"},8631:{f:"A"},8634:{f:"A"},8635:{f:"A"},8638:{f:"A"},8639:{f:"A"},8642:{f:"A"},8643:{f:"A"},8644:{f:"A"},8646:{f:"A"},8647:{f:"A"},8648:{f:"A"},8649:{f:"A"},8650:{f:"A"},8651:{f:"A"},8653:{f:"A"},8654:{f:"A"},8655:{f:"A"},8666:{f:"A"},8667:{f:"A"},8669:{f:"A"},8672:{f:"A"},8674:{f:"A"},8705:{f:"A"},8708:{c:"\\2203\\338"},8710:{c:"\\394"},8716:{c:"\\220B\\338"},8717:{f:"A"},8719:{f:"S1"},8720:{f:"S1"},8721:{f:"S1"},8724:{f:"A"},8737:{f:"A"},8738:{f:"A"},8740:{f:"A"},8742:{f:"A"},8748:{f:"S1"},8749:{f:"S1"},8750:{f:"S1"},8756:{f:"A"},8757:{f:"A"},8765:{f:"A"},8769:{f:"A"},8770:{f:"A"},8772:{c:"\\2243\\338"},8775:{c:"\\2246",f:"A"},8777:{c:"\\2248\\338"},8778:{f:"A"},8782:{f:"A"},8783:{f:"A"},8785:{f:"A"},8786:{f:"A"},8787:{f:"A"},8790:{f:"A"},8791:{f:"A"},8796:{f:"A"},8802:{c:"\\2261\\338"},8806:{f:"A"},8807:{f:"A"},8808:{f:"A"},8809:{f:"A"},8812:{f:"A"},8813:{c:"\\224D\\338"},8814:{f:"A"},8815:{f:"A"},8816:{f:"A"},8817:{f:"A"},8818:{f:"A"},8819:{f:"A"},8820:{c:"\\2272\\338"},8821:{c:"\\2273\\338"},8822:{f:"A"},8823:{f:"A"},8824:{c:"\\2276\\338"},8825:{c:"\\2277\\338"},8828:{f:"A"},8829:{f:"A"},8830:{f:"A"},8831:{f:"A"},8832:{f:"A"},8833:{f:"A"},8836:{c:"\\2282\\338"},8837:{c:"\\2283\\338"},8840:{f:"A"},8841:{f:"A"},8842:{f:"A"},8843:{f:"A"},8847:{f:"A"},8848:{f:"A"},8858:{f:"A"},8859:{f:"A"},8861:{f:"A"},8862:{f:"A"},8863:{f:"A"},8864:{f:"A"},8865:{f:"A"},8873:{f:"A"},8874:{f:"A"},8876:{f:"A"},8877:{f:"A"},8878:{f:"A"},8879:{f:"A"},8882:{f:"A"},8883:{f:"A"},8884:{f:"A"},8885:{f:"A"},8888:{f:"A"},8890:{f:"A"},8891:{f:"A"},8892:{f:"A"},8896:{f:"S1"},8897:{f:"S1"},8898:{f:"S1"},8899:{f:"S1"},8903:{f:"A"},8905:{f:"A"},8906:{f:"A"},8907:{f:"A"},8908:{f:"A"},8909:{f:"A"},8910:{f:"A"},8911:{f:"A"},8912:{f:"A"},8913:{f:"A"},8914:{f:"A"},8915:{f:"A"},8916:{f:"A"},8918:{f:"A"},8919:{f:"A"},8920:{f:"A"},8921:{f:"A"},8922:{f:"A"},8923:{f:"A"},8926:{f:"A"},8927:{f:"A"},8928:{f:"A"},8929:{f:"A"},8930:{c:"\\2291\\338"},8931:{c:"\\2292\\338"},8934:{f:"A"},8935:{f:"A"},8936:{f:"A"},8937:{f:"A"},8938:{f:"A"},8939:{f:"A"},8940:{f:"A"},8941:{f:"A"},8965:{c:"\\22BC",f:"A"},8966:{c:"\\2A5E",f:"A"},8988:{c:"\\250C",f:"A"},8989:{c:"\\2510",f:"A"},8990:{c:"\\2514",f:"A"},8991:{c:"\\2518",f:"A"},9001:{c:"\\27E8"},9002:{c:"\\27E9"},9168:{f:"S1"},9416:{f:"A"},9484:{f:"A"},9488:{f:"A"},9492:{f:"A"},9496:{f:"A"},9585:{f:"A"},9586:{f:"A"},9632:{f:"A"},9633:{f:"A"},9642:{c:"\\25A0",f:"A"},9650:{f:"A"},9652:{c:"\\25B2",f:"A"},9653:{c:"\\25B3"},9654:{f:"A"},9656:{c:"\\25B6",f:"A"},9660:{f:"A"},9662:{c:"\\25BC",f:"A"},9663:{c:"\\25BD"},9664:{f:"A"},9666:{c:"\\25C0",f:"A"},9674:{f:"A"},9723:{c:"\\25A1",f:"A"},9724:{c:"\\25A0",f:"A"},9733:{f:"A"},10003:{f:"A"},10016:{f:"A"},10072:{c:"\\2223"},10731:{f:"A"},10744:{c:"/",f:"I"},10752:{f:"S1"},10753:{f:"S1"},10754:{f:"S1"},10756:{f:"S1"},10758:{f:"S1"},10764:{c:"\\222C\\222C",f:"S1"},10799:{c:"\\D7"},10846:{f:"A"},10877:{f:"A"},10878:{f:"A"},10885:{f:"A"},10886:{f:"A"},10887:{f:"A"},10888:{f:"A"},10889:{f:"A"},10890:{f:"A"},10891:{f:"A"},10892:{f:"A"},10901:{f:"A"},10902:{f:"A"},10933:{f:"A"},10934:{f:"A"},10935:{f:"A"},10936:{f:"A"},10937:{f:"A"},10938:{f:"A"},10949:{f:"A"},10950:{f:"A"},10955:{f:"A"},10956:{f:"A"},12296:{c:"\\27E8"},12297:{c:"\\27E9"},57350:{f:"A"},57351:{f:"A"},57352:{f:"A"},57353:{f:"A"},57356:{f:"A"},57357:{f:"A"},57358:{f:"A"},57359:{f:"A"},57360:{f:"A"},57361:{f:"A"},57366:{f:"A"},57367:{f:"A"},57368:{f:"A"},57369:{f:"A"},57370:{f:"A"},57371:{f:"A"},119808:{c:"A",f:"B"},119809:{c:"B",f:"B"},119810:{c:"C",f:"B"},119811:{c:"D",f:"B"},119812:{c:"E",f:"B"},119813:{c:"F",f:"B"},119814:{c:"G",f:"B"},119815:{c:"H",f:"B"},119816:{c:"I",f:"B"},119817:{c:"J",f:"B"},119818:{c:"K",f:"B"},119819:{c:"L",f:"B"},119820:{c:"M",f:"B"},119821:{c:"N",f:"B"},119822:{c:"O",f:"B"},119823:{c:"P",f:"B"},119824:{c:"Q",f:"B"},119825:{c:"R",f:"B"},119826:{c:"S",f:"B"},119827:{c:"T",f:"B"},119828:{c:"U",f:"B"},119829:{c:"V",f:"B"},119830:{c:"W",f:"B"},119831:{c:"X",f:"B"},119832:{c:"Y",f:"B"},119833:{c:"Z",f:"B"},119834:{c:"a",f:"B"},119835:{c:"b",f:"B"},119836:{c:"c",f:"B"},119837:{c:"d",f:"B"},119838:{c:"e",f:"B"},119839:{c:"f",f:"B"},119840:{c:"g",f:"B"},119841:{c:"h",f:"B"},119842:{c:"i",f:"B"},119843:{c:"j",f:"B"},119844:{c:"k",f:"B"},119845:{c:"l",f:"B"},119846:{c:"m",f:"B"},119847:{c:"n",f:"B"},119848:{c:"o",f:"B"},119849:{c:"p",f:"B"},119850:{c:"q",f:"B"},119851:{c:"r",f:"B"},119852:{c:"s",f:"B"},119853:{c:"t",f:"B"},119854:{c:"u",f:"B"},119855:{c:"v",f:"B"},119856:{c:"w",f:"B"},119857:{c:"x",f:"B"},119858:{c:"y",f:"B"},119859:{c:"z",f:"B"},119860:{c:"A",f:"I"},119861:{c:"B",f:"I"},119862:{c:"C",f:"I"},119863:{c:"D",f:"I"},119864:{c:"E",f:"I"},119865:{c:"F",f:"I"},119866:{c:"G",f:"I"},119867:{c:"H",f:"I"},119868:{c:"I",f:"I"},119869:{c:"J",f:"I"},119870:{c:"K",f:"I"},119871:{c:"L",f:"I"},119872:{c:"M",f:"I"},119873:{c:"N",f:"I"},119874:{c:"O",f:"I"},119875:{c:"P",f:"I"},119876:{c:"Q",f:"I"},119877:{c:"R",f:"I"},119878:{c:"S",f:"I"},119879:{c:"T",f:"I"},119880:{c:"U",f:"I"},119881:{c:"V",f:"I"},119882:{c:"W",f:"I"},119883:{c:"X",f:"I"},119884:{c:"Y",f:"I"},119885:{c:"Z",f:"I"},119886:{c:"a",f:"I"},119887:{c:"b",f:"I"},119888:{c:"c",f:"I"},119889:{c:"d",f:"I"},119890:{c:"e",f:"I"},119891:{c:"f",f:"I"},119892:{c:"g",f:"I"},119894:{c:"i",f:"I"},119895:{c:"j",f:"I"},119896:{c:"k",f:"I"},119897:{c:"l",f:"I"},119898:{c:"m",f:"I"},119899:{c:"n",f:"I"},119900:{c:"o",f:"I"},119901:{c:"p",f:"I"},119902:{c:"q",f:"I"},119903:{c:"r",f:"I"},119904:{c:"s",f:"I"},119905:{c:"t",f:"I"},119906:{c:"u",f:"I"},119907:{c:"v",f:"I"},119908:{c:"w",f:"I"},119909:{c:"x",f:"I"},119910:{c:"y",f:"I"},119911:{c:"z",f:"I"},119912:{c:"A",f:"BI"},119913:{c:"B",f:"BI"},119914:{c:"C",f:"BI"},119915:{c:"D",f:"BI"},119916:{c:"E",f:"BI"},119917:{c:"F",f:"BI"},119918:{c:"G",f:"BI"},119919:{c:"H",f:"BI"},119920:{c:"I",f:"BI"},119921:{c:"J",f:"BI"},119922:{c:"K",f:"BI"},119923:{c:"L",f:"BI"},119924:{c:"M",f:"BI"},119925:{c:"N",f:"BI"},119926:{c:"O",f:"BI"},119927:{c:"P",f:"BI"},119928:{c:"Q",f:"BI"},119929:{c:"R",f:"BI"},119930:{c:"S",f:"BI"},119931:{c:"T",f:"BI"},119932:{c:"U",f:"BI"},119933:{c:"V",f:"BI"},119934:{c:"W",f:"BI"},119935:{c:"X",f:"BI"},119936:{c:"Y",f:"BI"},119937:{c:"Z",f:"BI"},119938:{c:"a",f:"BI"},119939:{c:"b",f:"BI"},119940:{c:"c",f:"BI"},119941:{c:"d",f:"BI"},119942:{c:"e",f:"BI"},119943:{c:"f",f:"BI"},119944:{c:"g",f:"BI"},119945:{c:"h",f:"BI"},119946:{c:"i",f:"BI"},119947:{c:"j",f:"BI"},119948:{c:"k",f:"BI"},119949:{c:"l",f:"BI"},119950:{c:"m",f:"BI"},119951:{c:"n",f:"BI"},119952:{c:"o",f:"BI"},119953:{c:"p",f:"BI"},119954:{c:"q",f:"BI"},119955:{c:"r",f:"BI"},119956:{c:"s",f:"BI"},119957:{c:"t",f:"BI"},119958:{c:"u",f:"BI"},119959:{c:"v",f:"BI"},119960:{c:"w",f:"BI"},119961:{c:"x",f:"BI"},119962:{c:"y",f:"BI"},119963:{c:"z",f:"BI"},119964:{c:"A",f:"SC"},119966:{c:"C",f:"SC"},119967:{c:"D",f:"SC"},119970:{c:"G",f:"SC"},119973:{c:"J",f:"SC"},119974:{c:"K",f:"SC"},119977:{c:"N",f:"SC"},119978:{c:"O",f:"SC"},119979:{c:"P",f:"SC"},119980:{c:"Q",f:"SC"},119982:{c:"S",f:"SC"},119983:{c:"T",f:"SC"},119984:{c:"U",f:"SC"},119985:{c:"V",f:"SC"},119986:{c:"W",f:"SC"},119987:{c:"X",f:"SC"},119988:{c:"Y",f:"SC"},119989:{c:"Z",f:"SC"},120068:{c:"A",f:"FR"},120069:{c:"B",f:"FR"},120071:{c:"D",f:"FR"},120072:{c:"E",f:"FR"},120073:{c:"F",f:"FR"},120074:{c:"G",f:"FR"},120077:{c:"J",f:"FR"},120078:{c:"K",f:"FR"},120079:{c:"L",f:"FR"},120080:{c:"M",f:"FR"},120081:{c:"N",f:"FR"},120082:{c:"O",f:"FR"},120083:{c:"P",f:"FR"},120084:{c:"Q",f:"FR"},120086:{c:"S",f:"FR"},120087:{c:"T",f:"FR"},120088:{c:"U",f:"FR"},120089:{c:"V",f:"FR"},120090:{c:"W",f:"FR"},120091:{c:"X",f:"FR"},120092:{c:"Y",f:"FR"},120094:{c:"a",f:"FR"},120095:{c:"b",f:"FR"},120096:{c:"c",f:"FR"},120097:{c:"d",f:"FR"},120098:{c:"e",f:"FR"},120099:{c:"f",f:"FR"},120100:{c:"g",f:"FR"},120101:{c:"h",f:"FR"},120102:{c:"i",f:"FR"},120103:{c:"j",f:"FR"},120104:{c:"k",f:"FR"},120105:{c:"l",f:"FR"},120106:{c:"m",f:"FR"},120107:{c:"n",f:"FR"},120108:{c:"o",f:"FR"},120109:{c:"p",f:"FR"},120110:{c:"q",f:"FR"},120111:{c:"r",f:"FR"},120112:{c:"s",f:"FR"},120113:{c:"t",f:"FR"},120114:{c:"u",f:"FR"},120115:{c:"v",f:"FR"},120116:{c:"w",f:"FR"},120117:{c:"x",f:"FR"},120118:{c:"y",f:"FR"},120119:{c:"z",f:"FR"},120120:{c:"A",f:"A"},120121:{c:"B",f:"A"},120123:{c:"D",f:"A"},120124:{c:"E",f:"A"},120125:{c:"F",f:"A"},120126:{c:"G",f:"A"},120128:{c:"I",f:"A"},120129:{c:"J",f:"A"},120130:{c:"K",f:"A"},120131:{c:"L",f:"A"},120132:{c:"M",f:"A"},120134:{c:"O",f:"A"},120138:{c:"S",f:"A"},120139:{c:"T",f:"A"},120140:{c:"U",f:"A"},120141:{c:"V",f:"A"},120142:{c:"W",f:"A"},120143:{c:"X",f:"A"},120144:{c:"Y",f:"A"},120172:{c:"A",f:"FRB"},120173:{c:"B",f:"FRB"},120174:{c:"C",f:"FRB"},120175:{c:"D",f:"FRB"},120176:{c:"E",f:"FRB"},120177:{c:"F",f:"FRB"},120178:{c:"G",f:"FRB"},120179:{c:"H",f:"FRB"},120180:{c:"I",f:"FRB"},120181:{c:"J",f:"FRB"},120182:{c:"K",f:"FRB"},120183:{c:"L",f:"FRB"},120184:{c:"M",f:"FRB"},120185:{c:"N",f:"FRB"},120186:{c:"O",f:"FRB"},120187:{c:"P",f:"FRB"},120188:{c:"Q",f:"FRB"},120189:{c:"R",f:"FRB"},120190:{c:"S",f:"FRB"},120191:{c:"T",f:"FRB"},120192:{c:"U",f:"FRB"},120193:{c:"V",f:"FRB"},120194:{c:"W",f:"FRB"},120195:{c:"X",f:"FRB"},120196:{c:"Y",f:"FRB"},120197:{c:"Z",f:"FRB"},120198:{c:"a",f:"FRB"},120199:{c:"b",f:"FRB"},120200:{c:"c",f:"FRB"},120201:{c:"d",f:"FRB"},120202:{c:"e",f:"FRB"},120203:{c:"f",f:"FRB"},120204:{c:"g",f:"FRB"},120205:{c:"h",f:"FRB"},120206:{c:"i",f:"FRB"},120207:{c:"j",f:"FRB"},120208:{c:"k",f:"FRB"},120209:{c:"l",f:"FRB"},120210:{c:"m",f:"FRB"},120211:{c:"n",f:"FRB"},120212:{c:"o",f:"FRB"},120213:{c:"p",f:"FRB"},120214:{c:"q",f:"FRB"},120215:{c:"r",f:"FRB"},120216:{c:"s",f:"FRB"},120217:{c:"t",f:"FRB"},120218:{c:"u",f:"FRB"},120219:{c:"v",f:"FRB"},120220:{c:"w",f:"FRB"},120221:{c:"x",f:"FRB"},120222:{c:"y",f:"FRB"},120223:{c:"z",f:"FRB"},120224:{c:"A",f:"SS"},120225:{c:"B",f:"SS"},120226:{c:"C",f:"SS"},120227:{c:"D",f:"SS"},120228:{c:"E",f:"SS"},120229:{c:"F",f:"SS"},120230:{c:"G",f:"SS"},120231:{c:"H",f:"SS"},120232:{c:"I",f:"SS"},120233:{c:"J",f:"SS"},120234:{c:"K",f:"SS"},120235:{c:"L",f:"SS"},120236:{c:"M",f:"SS"},120237:{c:"N",f:"SS"},120238:{c:"O",f:"SS"},120239:{c:"P",f:"SS"},120240:{c:"Q",f:"SS"},120241:{c:"R",f:"SS"},120242:{c:"S",f:"SS"},120243:{c:"T",f:"SS"},120244:{c:"U",f:"SS"},120245:{c:"V",f:"SS"},120246:{c:"W",f:"SS"},120247:{c:"X",f:"SS"},120248:{c:"Y",f:"SS"},120249:{c:"Z",f:"SS"},120250:{c:"a",f:"SS"},120251:{c:"b",f:"SS"},120252:{c:"c",f:"SS"},120253:{c:"d",f:"SS"},120254:{c:"e",f:"SS"},120255:{c:"f",f:"SS"},120256:{c:"g",f:"SS"},120257:{c:"h",f:"SS"},120258:{c:"i",f:"SS"},120259:{c:"j",f:"SS"},120260:{c:"k",f:"SS"},120261:{c:"l",f:"SS"},120262:{c:"m",f:"SS"},120263:{c:"n",f:"SS"},120264:{c:"o",f:"SS"},120265:{c:"p",f:"SS"},120266:{c:"q",f:"SS"},120267:{c:"r",f:"SS"},120268:{c:"s",f:"SS"},120269:{c:"t",f:"SS"},120270:{c:"u",f:"SS"},120271:{c:"v",f:"SS"},120272:{c:"w",f:"SS"},120273:{c:"x",f:"SS"},120274:{c:"y",f:"SS"},120275:{c:"z",f:"SS"},120276:{c:"A",f:"SSB"},120277:{c:"B",f:"SSB"},120278:{c:"C",f:"SSB"},120279:{c:"D",f:"SSB"},120280:{c:"E",f:"SSB"},120281:{c:"F",f:"SSB"},120282:{c:"G",f:"SSB"},120283:{c:"H",f:"SSB"},120284:{c:"I",f:"SSB"},120285:{c:"J",f:"SSB"},120286:{c:"K",f:"SSB"},120287:{c:"L",f:"SSB"},120288:{c:"M",f:"SSB"},120289:{c:"N",f:"SSB"},120290:{c:"O",f:"SSB"},120291:{c:"P",f:"SSB"},120292:{c:"Q",f:"SSB"},120293:{c:"R",f:"SSB"},120294:{c:"S",f:"SSB"},120295:{c:"T",f:"SSB"},120296:{c:"U",f:"SSB"},120297:{c:"V",f:"SSB"},120298:{c:"W",f:"SSB"},120299:{c:"X",f:"SSB"},120300:{c:"Y",f:"SSB"},120301:{c:"Z",f:"SSB"},120302:{c:"a",f:"SSB"},120303:{c:"b",f:"SSB"},120304:{c:"c",f:"SSB"},120305:{c:"d",f:"SSB"},120306:{c:"e",f:"SSB"},120307:{c:"f",f:"SSB"},120308:{c:"g",f:"SSB"},120309:{c:"h",f:"SSB"},120310:{c:"i",f:"SSB"},120311:{c:"j",f:"SSB"},120312:{c:"k",f:"SSB"},120313:{c:"l",f:"SSB"},120314:{c:"m",f:"SSB"},120315:{c:"n",f:"SSB"},120316:{c:"o",f:"SSB"},120317:{c:"p",f:"SSB"},120318:{c:"q",f:"SSB"},120319:{c:"r",f:"SSB"},120320:{c:"s",f:"SSB"},120321:{c:"t",f:"SSB"},120322:{c:"u",f:"SSB"},120323:{c:"v",f:"SSB"},120324:{c:"w",f:"SSB"},120325:{c:"x",f:"SSB"},120326:{c:"y",f:"SSB"},120327:{c:"z",f:"SSB"},120328:{c:"A",f:"SSI"},120329:{c:"B",f:"SSI"},120330:{c:"C",f:"SSI"},120331:{c:"D",f:"SSI"},120332:{c:"E",f:"SSI"},120333:{c:"F",f:"SSI"},120334:{c:"G",f:"SSI"},120335:{c:"H",f:"SSI"},120336:{c:"I",f:"SSI"},120337:{c:"J",f:"SSI"},120338:{c:"K",f:"SSI"},120339:{c:"L",f:"SSI"},120340:{c:"M",f:"SSI"},120341:{c:"N",f:"SSI"},120342:{c:"O",f:"SSI"},120343:{c:"P",f:"SSI"},120344:{c:"Q",f:"SSI"},120345:{c:"R",f:"SSI"},120346:{c:"S",f:"SSI"},120347:{c:"T",f:"SSI"},120348:{c:"U",f:"SSI"},120349:{c:"V",f:"SSI"},120350:{c:"W",f:"SSI"},120351:{c:"X",f:"SSI"},120352:{c:"Y",f:"SSI"},120353:{c:"Z",f:"SSI"},120354:{c:"a",f:"SSI"},120355:{c:"b",f:"SSI"},120356:{c:"c",f:"SSI"},120357:{c:"d",f:"SSI"},120358:{c:"e",f:"SSI"},120359:{c:"f",f:"SSI"},120360:{c:"g",f:"SSI"},120361:{c:"h",f:"SSI"},120362:{c:"i",f:"SSI"},120363:{c:"j",f:"SSI"},120364:{c:"k",f:"SSI"},120365:{c:"l",f:"SSI"},120366:{c:"m",f:"SSI"},120367:{c:"n",f:"SSI"},120368:{c:"o",f:"SSI"},120369:{c:"p",f:"SSI"},120370:{c:"q",f:"SSI"},120371:{c:"r",f:"SSI"},120372:{c:"s",f:"SSI"},120373:{c:"t",f:"SSI"},120374:{c:"u",f:"SSI"},120375:{c:"v",f:"SSI"},120376:{c:"w",f:"SSI"},120377:{c:"x",f:"SSI"},120378:{c:"y",f:"SSI"},120379:{c:"z",f:"SSI"},120432:{c:"A",f:"T"},120433:{c:"B",f:"T"},120434:{c:"C",f:"T"},120435:{c:"D",f:"T"},120436:{c:"E",f:"T"},120437:{c:"F",f:"T"},120438:{c:"G",f:"T"},120439:{c:"H",f:"T"},120440:{c:"I",f:"T"},120441:{c:"J",f:"T"},120442:{c:"K",f:"T"},120443:{c:"L",f:"T"},120444:{c:"M",f:"T"},120445:{c:"N",f:"T"},120446:{c:"O",f:"T"},120447:{c:"P",f:"T"},120448:{c:"Q",f:"T"},120449:{c:"R",f:"T"},120450:{c:"S",f:"T"},120451:{c:"T",f:"T"},120452:{c:"U",f:"T"},120453:{c:"V",f:"T"},120454:{c:"W",f:"T"},120455:{c:"X",f:"T"},120456:{c:"Y",f:"T"},120457:{c:"Z",f:"T"},120458:{c:"a",f:"T"},120459:{c:"b",f:"T"},120460:{c:"c",f:"T"},120461:{c:"d",f:"T"},120462:{c:"e",f:"T"},120463:{c:"f",f:"T"},120464:{c:"g",f:"T"},120465:{c:"h",f:"T"},120466:{c:"i",f:"T"},120467:{c:"j",f:"T"},120468:{c:"k",f:"T"},120469:{c:"l",f:"T"},120470:{c:"m",f:"T"},120471:{c:"n",f:"T"},120472:{c:"o",f:"T"},120473:{c:"p",f:"T"},120474:{c:"q",f:"T"},120475:{c:"r",f:"T"},120476:{c:"s",f:"T"},120477:{c:"t",f:"T"},120478:{c:"u",f:"T"},120479:{c:"v",f:"T"},120480:{c:"w",f:"T"},120481:{c:"x",f:"T"},120482:{c:"y",f:"T"},120483:{c:"z",f:"T"},120488:{c:"A",f:"B"},120489:{c:"B",f:"B"},120490:{c:"\\393",f:"B"},120491:{c:"\\394",f:"B"},120492:{c:"E",f:"B"},120493:{c:"Z",f:"B"},120494:{c:"H",f:"B"},120495:{c:"\\398",f:"B"},120496:{c:"I",f:"B"},120497:{c:"K",f:"B"},120498:{c:"\\39B",f:"B"},120499:{c:"M",f:"B"},120500:{c:"N",f:"B"},120501:{c:"\\39E",f:"B"},120502:{c:"O",f:"B"},120503:{c:"\\3A0",f:"B"},120504:{c:"P",f:"B"},120506:{c:"\\3A3",f:"B"},120507:{c:"T",f:"B"},120508:{c:"\\3A5",f:"B"},120509:{c:"\\3A6",f:"B"},120510:{c:"X",f:"B"},120511:{c:"\\3A8",f:"B"},120512:{c:"\\3A9",f:"B"},120513:{c:"\\2207",f:"B"},120546:{c:"A",f:"I"},120547:{c:"B",f:"I"},120548:{c:"\\393",f:"I"},120549:{c:"\\394",f:"I"},120550:{c:"E",f:"I"},120551:{c:"Z",f:"I"},120552:{c:"H",f:"I"},120553:{c:"\\398",f:"I"},120554:{c:"I",f:"I"},120555:{c:"K",f:"I"},120556:{c:"\\39B",f:"I"},120557:{c:"M",f:"I"},120558:{c:"N",f:"I"},120559:{c:"\\39E",f:"I"},120560:{c:"O",f:"I"},120561:{c:"\\3A0",f:"I"},120562:{c:"P",f:"I"},120564:{c:"\\3A3",f:"I"},120565:{c:"T",f:"I"},120566:{c:"\\3A5",f:"I"},120567:{c:"\\3A6",f:"I"},120568:{c:"X",f:"I"},120569:{c:"\\3A8",f:"I"},120570:{c:"\\3A9",f:"I"},120572:{c:"\\3B1",f:"I"},120573:{c:"\\3B2",f:"I"},120574:{c:"\\3B3",f:"I"},120575:{c:"\\3B4",f:"I"},120576:{c:"\\3B5",f:"I"},120577:{c:"\\3B6",f:"I"},120578:{c:"\\3B7",f:"I"},120579:{c:"\\3B8",f:"I"},120580:{c:"\\3B9",f:"I"},120581:{c:"\\3BA",f:"I"},120582:{c:"\\3BB",f:"I"},120583:{c:"\\3BC",f:"I"},120584:{c:"\\3BD",f:"I"},120585:{c:"\\3BE",f:"I"},120586:{c:"\\3BF",f:"I"},120587:{c:"\\3C0",f:"I"},120588:{c:"\\3C1",f:"I"},120589:{c:"\\3C2",f:"I"},120590:{c:"\\3C3",f:"I"},120591:{c:"\\3C4",f:"I"},120592:{c:"\\3C5",f:"I"},120593:{c:"\\3C6",f:"I"},120594:{c:"\\3C7",f:"I"},120595:{c:"\\3C8",f:"I"},120596:{c:"\\3C9",f:"I"},120597:{c:"\\2202"},120598:{c:"\\3F5",f:"I"},120599:{c:"\\3D1",f:"I"},120600:{c:"\\E009",f:"A"},120601:{c:"\\3D5",f:"I"},120602:{c:"\\3F1",f:"I"},120603:{c:"\\3D6",f:"I"},120604:{c:"A",f:"BI"},120605:{c:"B",f:"BI"},120606:{c:"\\393",f:"BI"},120607:{c:"\\394",f:"BI"},120608:{c:"E",f:"BI"},120609:{c:"Z",f:"BI"},120610:{c:"H",f:"BI"},120611:{c:"\\398",f:"BI"},120612:{c:"I",f:"BI"},120613:{c:"K",f:"BI"},120614:{c:"\\39B",f:"BI"},120615:{c:"M",f:"BI"},120616:{c:"N",f:"BI"},120617:{c:"\\39E",f:"BI"},120618:{c:"O",f:"BI"},120619:{c:"\\3A0",f:"BI"},120620:{c:"P",f:"BI"},120622:{c:"\\3A3",f:"BI"},120623:{c:"T",f:"BI"},120624:{c:"\\3A5",f:"BI"},120625:{c:"\\3A6",f:"BI"},120626:{c:"X",f:"BI"},120627:{c:"\\3A8",f:"BI"},120628:{c:"\\3A9",f:"BI"},120630:{c:"\\3B1",f:"BI"},120631:{c:"\\3B2",f:"BI"},120632:{c:"\\3B3",f:"BI"},120633:{c:"\\3B4",f:"BI"},120634:{c:"\\3B5",f:"BI"},120635:{c:"\\3B6",f:"BI"},120636:{c:"\\3B7",f:"BI"},120637:{c:"\\3B8",f:"BI"},120638:{c:"\\3B9",f:"BI"},120639:{c:"\\3BA",f:"BI"},120640:{c:"\\3BB",f:"BI"},120641:{c:"\\3BC",f:"BI"},120642:{c:"\\3BD",f:"BI"},120643:{c:"\\3BE",f:"BI"},120644:{c:"\\3BF",f:"BI"},120645:{c:"\\3C0",f:"BI"},120646:{c:"\\3C1",f:"BI"},120647:{c:"\\3C2",f:"BI"},120648:{c:"\\3C3",f:"BI"},120649:{c:"\\3C4",f:"BI"},120650:{c:"\\3C5",f:"BI"},120651:{c:"\\3C6",f:"BI"},120652:{c:"\\3C7",f:"BI"},120653:{c:"\\3C8",f:"BI"},120654:{c:"\\3C9",f:"BI"},120655:{c:"\\2202",f:"B"},120656:{c:"\\3F5",f:"BI"},120657:{c:"\\3D1",f:"BI"},120658:{c:"\\E009",f:"A"},120659:{c:"\\3D5",f:"BI"},120660:{c:"\\3F1",f:"BI"},120661:{c:"\\3D6",f:"BI"},120662:{c:"A",f:"SSB"},120663:{c:"B",f:"SSB"},120664:{c:"\\393",f:"SSB"},120665:{c:"\\394",f:"SSB"},120666:{c:"E",f:"SSB"},120667:{c:"Z",f:"SSB"},120668:{c:"H",f:"SSB"},120669:{c:"\\398",f:"SSB"},120670:{c:"I",f:"SSB"},120671:{c:"K",f:"SSB"},120672:{c:"\\39B",f:"SSB"},120673:{c:"M",f:"SSB"},120674:{c:"N",f:"SSB"},120675:{c:"\\39E",f:"SSB"},120676:{c:"O",f:"SSB"},120677:{c:"\\3A0",f:"SSB"},120678:{c:"P",f:"SSB"},120680:{c:"\\3A3",f:"SSB"},120681:{c:"T",f:"SSB"},120682:{c:"\\3A5",f:"SSB"},120683:{c:"\\3A6",f:"SSB"},120684:{c:"X",f:"SSB"},120685:{c:"\\3A8",f:"SSB"},120686:{c:"\\3A9",f:"SSB"},120782:{c:"0",f:"B"},120783:{c:"1",f:"B"},120784:{c:"2",f:"B"},120785:{c:"3",f:"B"},120786:{c:"4",f:"B"},120787:{c:"5",f:"B"},120788:{c:"6",f:"B"},120789:{c:"7",f:"B"},120790:{c:"8",f:"B"},120791:{c:"9",f:"B"},120802:{c:"0",f:"SS"},120803:{c:"1",f:"SS"},120804:{c:"2",f:"SS"},120805:{c:"3",f:"SS"},120806:{c:"4",f:"SS"},120807:{c:"5",f:"SS"},120808:{c:"6",f:"SS"},120809:{c:"7",f:"SS"},120810:{c:"8",f:"SS"},120811:{c:"9",f:"SS"},120812:{c:"0",f:"SSB"},120813:{c:"1",f:"SSB"},120814:{c:"2",f:"SSB"},120815:{c:"3",f:"SSB"},120816:{c:"4",f:"SSB"},120817:{c:"5",f:"SSB"},120818:{c:"6",f:"SSB"},120819:{c:"7",f:"SSB"},120820:{c:"8",f:"SSB"},120821:{c:"9",f:"SSB"},120822:{c:"0",f:"T"},120823:{c:"1",f:"T"},120824:{c:"2",f:"T"},120825:{c:"3",f:"T"},120826:{c:"4",f:"T"},120827:{c:"5",f:"T"},120828:{c:"6",f:"T"},120829:{c:"7",f:"T"},120830:{c:"8",f:"T"},120831:{c:"9",f:"T"}})},3518:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.sansSerifBoldItalic=void 0;var t=i(73),e=i(6949);f.sansSerifBoldItalic=t.AddCSS(e.sansSerifBoldItalic,{305:{f:"SSB"},567:{f:"SSB"}})},965:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.sansSerifBold=void 0;var t=i(73),e=i(5193);f.sansSerifBold=t.AddCSS(e.sansSerifBold,{8213:{c:"\\2014"},8215:{c:"_"},8260:{c:"/"},8710:{c:"\\394"}})},9169:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.sansSerifItalic=void 0;var t=i(73),e=i(2632);f.sansSerifItalic=t.AddCSS(e.sansSerifItalic,{913:{c:"A"},914:{c:"B"},917:{c:"E"},918:{c:"Z"},919:{c:"H"},921:{c:"I"},922:{c:"K"},924:{c:"M"},925:{c:"N"},927:{c:"O"},929:{c:"P"},932:{c:"T"},935:{c:"X"},8213:{c:"\\2014"},8215:{c:"_"},8260:{c:"/"},8710:{c:"\\394"}})},6736:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.sansSerif=void 0;var t=i(73),e=i(4214);f.sansSerif=t.AddCSS(e.sansSerif,{913:{c:"A"},914:{c:"B"},917:{c:"E"},918:{c:"Z"},919:{c:"H"},921:{c:"I"},922:{c:"K"},924:{c:"M"},925:{c:"N"},927:{c:"O"},929:{c:"P"},932:{c:"T"},935:{c:"X"},8213:{c:"\\2014"},8215:{c:"_"},8260:{c:"/"},8710:{c:"\\394"}})},2290:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.scriptBold=void 0;var t=i(6466);Object.defineProperty(f,"scriptBold",{enumerable:!0,get:function(){return t.scriptBold}})},3012:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.script=void 0;var t=i(3776);Object.defineProperty(f,"script",{enumerable:!0,get:function(){return t.script}})},8787:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.smallop=void 0;var t=i(73),e=i(7405);f.smallop=t.AddCSS(e.smallop,{8260:{c:"/"},9001:{c:"\\27E8"},9002:{c:"\\27E9"},10072:{c:"\\2223"},10764:{c:"\\222C\\222C"},12296:{c:"\\27E8"},12297:{c:"\\27E9"}})},5392:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texCalligraphicBold=void 0;var t=i(73),e=i(8105);f.texCalligraphicBold=t.AddCSS(e.texCalligraphicBold,{305:{f:"B"},567:{f:"B"}})},6318:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texCalligraphic=void 0;var t=i(2518);Object.defineProperty(f,"texCalligraphic",{enumerable:!0,get:function(){return t.texCalligraphic}})},5351:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texMathit=void 0;var t=i(5595);Object.defineProperty(f,"texMathit",{enumerable:!0,get:function(){return t.texMathit}})},873:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texOldstyleBold=void 0;var t=i(6357);Object.defineProperty(f,"texOldstyleBold",{enumerable:!0,get:function(){return t.texOldstyleBold}})},7611:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texOldstyle=void 0;var t=i(9474);Object.defineProperty(f,"texOldstyle",{enumerable:!0,get:function(){return t.texOldstyle}})},6590:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texSize3=void 0;var t=i(73),e=i(584);f.texSize3=t.AddCSS(e.texSize3,{8260:{c:"/"},9001:{c:"\\27E8"},9002:{c:"\\27E9"},12296:{c:"\\27E8"},12297:{c:"\\27E9"}})},8798:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texSize4=void 0;var t=i(73),e=i(4324);f.texSize4=t.AddCSS(e.texSize4,{8260:{c:"/"},9001:{c:"\\27E8"},9002:{c:"\\27E9"},12296:{c:"\\27E8"},12297:{c:"\\27E9"},57685:{c:"\\E153\\E152"},57686:{c:"\\E151\\E150"}})},2138:function(c,f,i){Object.defineProperty(f,"__esModule",{value:!0}),f.texVariant=void 0;var t=i(73),e=i(8135);f.texVariant=t.AddCSS(e.texVariant,{1008:{c:"\\E009"},8463:{f:""},8740:{c:"\\E006"},8742:{c:"\\E007"},8808:{c:"\\E00C"},8809:{c:"\\E00D"},8816:{c:"\\E011"},8817:{c:"\\E00E"},8840:{c:"\\E016"},8841:{c:"\\E018"},8842:{c:"\\E01A"},8843:{c:"\\E01B"},10887:{c:"\\E010"},10888:{c:"\\E00F"},10955:{c:"\\E017"},10956:{c:"\\E019"}})},2176:function(c,f){var i,t=this&&this.__extends||(i=function(c,f){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(c,f){c.__proto__=f}||function(c,f){for(var i in f)Object.prototype.hasOwnProperty.call(f,i)&&(c[i]=f[i])})(c,f)},function(c,f){if("function"!=typeof f&&null!==f)throw new TypeError("Class extends value "+String(f)+" is not a constructor or null");function t(){this.constructor=c}i(c,f),c.prototype=null===f?Object.create(f):(t.prototype=f.prototype,new t)}),e=this&&this.__assign||function(){return(e=Object.assign||function(c){for(var f,i=1,t=arguments.length;i0)&&!(t=s.next()).done;)r.push(t.value)}catch(c){e={error:c}}finally{try{t&&!t.done&&(i=s.return)&&i.call(s)}finally{if(e)throw e.error}}return r},r=this&&this.__spreadArray||function(c,f){for(var i=0,t=f.length,e=c.length;i=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};function o(e){return"object"==typeof e&&null!==e}function a(e,t){var r,i;try{for(var u=n(Object.keys(t)),c=u.next();!c.done;c=u.next()){var s=c.value;"__esModule"!==s&&(!o(e[s])||!o(t[s])||t[s]instanceof Promise?null!==t[s]&&void 0!==t[s]&&(e[s]=t[s]):a(e[s],t[s]))}}catch(e){r={error:e}}finally{try{c&&!c.done&&(i=u.return)&&i.call(u)}finally{if(r)throw r.error}}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.MathJax=t.combineWithMathJax=t.combineDefaults=t.combineConfig=t.isObject=void 0,t.isObject=o,t.combineConfig=a,t.combineDefaults=function e(t,r,a){var i,u;t[r]||(t[r]={}),t=t[r];try{for(var c=n(Object.keys(a)),s=c.next();!s.done;s=c.next()){var l=s.value;o(t[l])&&o(a[l])?e(t,l,a[l]):null==t[l]&&null!=a[l]&&(t[l]=a[l])}}catch(e){i={error:e}}finally{try{s&&!s.done&&(u=c.return)&&u.call(c)}finally{if(i)throw i.error}}return t},t.combineWithMathJax=function(e){return a(t.MathJax,e)},void 0===r.g.MathJax&&(r.g.MathJax={}),r.g.MathJax.version||(r.g.MathJax={version:"3.1.4",_:{},config:r.g.MathJax}),t.MathJax=r.g.MathJax},235:function(e,t,r){var n=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,r=t&&e[t],n=0;if(r)return r.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(t,"__esModule",{value:!0}),t.CONFIG=t.MathJax=t.Loader=t.PathFilters=t.PackageError=t.Package=void 0;var o=r(515),a=r(265),i=r(265);Object.defineProperty(t,"Package",{enumerable:!0,get:function(){return i.Package}}),Object.defineProperty(t,"PackageError",{enumerable:!0,get:function(){return i.PackageError}});var u,c=r(525);t.PathFilters={source:function(e){return t.CONFIG.source.hasOwnProperty(e.name)&&(e.name=t.CONFIG.source[e.name]),!0},normalize:function(e){var t=e.name;return t.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i)||(e.name="[mathjax]/"+t.replace(/^\.\//,"")),e.addExtension&&!t.match(/\.[^\/]+$/)&&(e.name+=".js"),!0},prefix:function(e){for(var r;(r=e.name.match(/^\[([^\]]*)\]/))&&t.CONFIG.paths.hasOwnProperty(r[1]);)e.name=t.CONFIG.paths[r[1]]+e.name.substr(r[0].length);return!0}},function(e){e.ready=function(){for(var e,t,r=[],o=0;o=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},u=this&&this.__spreadArray||function(e,t){for(var r=0,n=t.length,o=e.length;r=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},a=this&&this.__read||function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},i=this&&this.__spreadArray||function(e,t){for(var r=0,n=t.length,o=e.length;r=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},i=this&&this.__read||function(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,o,a=r.call(e),i=[];try{for(;(void 0===t||t-- >0)&&!(n=a.next()).done;)i.push(n.value)}catch(e){o={error:e}}finally{try{n&&!n.done&&(r=a.return)&&r.call(a)}finally{if(o)throw o.error}}return i},u=this&&this.__spreadArray||function(e,t){for(var r=0,n=t.length,o=e.length;rt.length}}}},e.prototype.add=function(t,r){void 0===r&&(r=e.DEFAULTPRIORITY);var n=this.items.length;do{n--}while(n>=0&&r=0&&this.items[t].item!==e);t>=0&&this.items.splice(t,1)},e.prototype.toArray=function(){return Array.from(this)},e.DEFAULTPRIORITY=5,e}();t.PrioritizedList=r}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n].call(a.exports,a,a.exports,r),a.exports}r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),function(){var e=r(515),t=r(235),n=r(265),o=r(388);(0,e.combineWithMathJax)({_:{components:{loader:t,package:n,startup:o}}});var a,i={tex:"[mathjax]/input/tex/extensions",sre:"[mathjax]/sre/"+("undefined"==typeof window?"sre-node":"sre_browser")},u=["[tex]/action","[tex]/ams","[tex]/amscd","[tex]/bbox","[tex]/boldsymbol","[tex]/braket","[tex]/bussproofs","[tex]/cancel","[tex]/color","[tex]/configmacros","[tex]/enclose","[tex]/extpfeil","[tex]/html","[tex]/mhchem","[tex]/newcommand","[tex]/noerrors","[tex]/noundefined","[tex]/physics","[tex]/require","[tex]/tagformat","[tex]/textmacros","[tex]/unicode","[tex]/verb"],c={startup:["loader"],"input/tex":["input/tex-base","[tex]/ams","[tex]/newcommand","[tex]/noundefined","[tex]/require","[tex]/autoload","[tex]/configmacros"],"input/tex-full":["input/tex-base","[tex]/all-packages"].concat(u),"[tex]/all-packages":u};function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r { + MathJax.typesetPromise?.( + document.querySelectorAll(".arithmatex") + ).catch((error) => console.error(error)); +}); diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 0000000..bee91a4 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,64 @@ +.md-typeset .arithmatex { + overflow-x: auto; +} + +.md-typeset .doc-contents { + overflow-wrap: anywhere; +} + +.md-typeset h1 code, +.md-typeset h2 code, +.md-typeset h3 code { + word-break: break-word; +} + +[data-md-color-scheme="slate"] { + --md-default-bg-color: #000000; + --md-default-bg-color--light: #050505; + --md-default-bg-color--lighter: #0a0a0a; + --md-default-bg-color--lightest: #111111; + --md-default-fg-color: #e8eef7; + --md-default-fg-color--light: #b3bfd1; + --md-default-fg-color--lighter: #7f8ba0; + --md-default-fg-color--lightest: #5d6880; + --md-code-bg-color: #050505; + --md-code-fg-color: #e4edf8; + --md-accent-fg-color: #7dd3fc; +} + +[data-md-color-scheme="slate"] .md-header, +[data-md-color-scheme="slate"] .md-tabs { + background: #000000; +} + +[data-md-color-scheme="slate"] .md-main, +[data-md-color-scheme="slate"] .md-main__inner, +[data-md-color-scheme="slate"] .md-content, +[data-md-color-scheme="slate"] .md-content__inner, +[data-md-color-scheme="slate"] .md-sidebar, +[data-md-color-scheme="slate"] .md-sidebar__scrollwrap { + background: #000000; +} + +[data-md-color-scheme="slate"] .md-typeset pre > code, +[data-md-color-scheme="slate"] .md-typeset code { + border: 1px solid rgba(125, 211, 252, 0.14); +} + +[data-md-color-scheme="slate"] .md-typeset table:not([class]) { + background: #050505; +} + +[data-md-color-scheme="slate"] .md-typeset table:not([class]) th { + background: rgba(125, 211, 252, 0.08); +} + +[data-md-color-scheme="slate"] .md-typeset .admonition, +[data-md-color-scheme="slate"] .md-typeset details { + background: #050505; + border-color: rgba(125, 211, 252, 0.2); +} + +[data-md-color-scheme="slate"] .md-typeset .arithmatex { + padding: 0.1rem 0; +} diff --git a/examples/eme.py b/examples/eme.py new file mode 100644 index 0000000..3a26dc8 --- /dev/null +++ b/examples/eme.py @@ -0,0 +1,221 @@ +""" +Mode-matching / EME example for a straight rib-waveguide interface. + +This example shows the intended user-facing workflow for `meanas.fdfd.eme` on a +simple straight interface: + +1. build two nearby waveguide cross-sections on a Yee grid, +2. solve a small set of guided modes on each side, +3. normalize those modes into E/H port fields, +4. assemble the interface scattering matrix with `meanas.fdfd.eme.get_s(...)`, +5. inspect the dominant modal coupling numerically and visually. +""" + +from __future__ import annotations + +import importlib +from typing import TYPE_CHECKING + +import numpy +from numpy import pi + +import gridlock +from gridlock import Extent + +from meanas.fdfd import eme, waveguide_2d +from meanas.fdmath import unvec + +if TYPE_CHECKING: + from types import ModuleType + + +WL = 1310.0 +DX = 40.0 +WIDTH = 400.0 +THF = 161.0 +THP = 77.0 +EPS_SI = 3.51 ** 2 +EPS_OX = 1.453 ** 2 +MODE_NUMBERS = numpy.array([0]) + + +def require_optional(name: str, package_name: str | None = None) -> ModuleType: + package_name = package_name or name + try: + return importlib.import_module(name) + except ImportError as exc: # pragma: no cover - user environment guard + raise SystemExit( + f"This example requires the optional package '{package_name}'. " + "Install example dependencies with `pip install -e './meanas[examples]'`.", + ) from exc + + +def build_geometry( + *, + dx: float = DX, + width: float = WIDTH, + thf: float = THF, + thp: float = THP, + eps_si: float = EPS_SI, + eps_ox: float = EPS_OX, + ) -> tuple[gridlock.Grid, numpy.ndarray, list[list[numpy.ndarray]], float]: + x0 = (width / 2) % dx + omega = 2 * pi / WL + + grid = gridlock.Grid( + [ + numpy.arange(-800, 800 + dx, dx), + numpy.arange(-400, 400 + dx, dx), + numpy.arange(-2 * dx, 2 * dx + dx, dx), + ], + periodic=True, + ) + epsilon = grid.allocate(eps_ox) + + grid.draw_cuboid( + epsilon, + foreground=eps_si, + x=Extent(center=x0, span=width + 1200), + y=Extent(min=0, max=thf), + z=Extent(min=-1e6, max=0), + ) + grid.draw_cuboid( + epsilon, + foreground=eps_ox, + x=Extent(max=-width / 2, span=300), + y=Extent(min=thp, max=1e6), + z=Extent(min=-1e6, max=0), + ) + grid.draw_cuboid( + epsilon, + foreground=eps_ox, + x=Extent(min=width / 2, span=300), + y=Extent(min=thp, max=1e6), + z=Extent(min=-1e6, max=0), + ) + + grid.draw_cuboid( + epsilon, + foreground=eps_si, + x=Extent(max=-(width / 2 + 600), span=240), + y=Extent(min=0, max=thf), + z=Extent(min=0, max=1e6), + ) + grid.draw_cuboid( + epsilon, + foreground=eps_si, + x=Extent(max=width / 2 + 600, span=240), + y=Extent(min=0, max=thf), + z=Extent(min=0, max=1e6), + ) + + dxes = [grid.dxyz, grid.autoshifted_dxyz()] + dxes_2d = [[d[0], d[1]] for d in dxes] + return grid, epsilon, dxes_2d, omega + + +def solve_cross_section_modes( + epsilon_slice: numpy.ndarray, + *, + omega: float, + dxes_2d: list[list[numpy.ndarray]], + mode_numbers: numpy.ndarray = MODE_NUMBERS, + ) -> tuple[list[tuple[numpy.ndarray, numpy.ndarray]], numpy.ndarray]: + e_xys, wavenumbers = waveguide_2d.solve_modes( + epsilon=epsilon_slice.ravel(), + omega=omega, + dxes=dxes_2d, + mode_numbers=mode_numbers, + ) + eh_fields = [ + waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + dxes=dxes_2d, + omega=omega, + epsilon=epsilon_slice.ravel(), + ) + for e_xy, wavenumber in zip(e_xys, wavenumbers, strict=True) + ] + return eh_fields, wavenumbers + + +def print_summary(ss: numpy.ndarray, wavenumbers_left: numpy.ndarray, wavenumbers_right: numpy.ndarray, omega: float) -> None: + n_left = len(wavenumbers_left) + left_neff = numpy.real(wavenumbers_left / omega) + right_neff = numpy.real(wavenumbers_right / omega) + + print('left effective indices:', ', '.join(f'{value:.5f}' for value in left_neff[:4])) + print('right effective indices:', ', '.join(f'{value:.5f}' for value in right_neff[:4])) + + reflection = abs(ss[0, 0]) ** 2 + transmission = abs(ss[n_left, 0]) ** 2 + total_output = numpy.sum(abs(ss[:, 0]) ** 2) + print(f'fundamental left-incident reflection |S_00|^2 = {reflection:.6f}') + print(f'fundamental left-to-right transmission |S_{n_left},0|^2 = {transmission:.6f}') + print(f'fundamental left-incident total output power = {total_output:.6f}') + + strongest = numpy.argsort(abs(ss[n_left:, 0]) ** 2)[::-1][:3] + print('dominant transmitted right-side modes for left mode 0:') + for mode_index in strongest: + print(f' mode {mode_index}: |S|^2 = {abs(ss[n_left + mode_index, 0]) ** 2:.6f}') + + +def plot_results( + *, + pyplot: ModuleType, + ss: numpy.ndarray, + left_mode: tuple[numpy.ndarray, numpy.ndarray], + right_mode: tuple[numpy.ndarray, numpy.ndarray], + shape_2d: tuple[int, int], + ) -> None: + fig_s, ax_s = pyplot.subplots() + image = ax_s.imshow(abs(ss) ** 2, origin='lower', cmap='magma') + fig_s.colorbar(image, ax=ax_s) + ax_s.set_title('Interface scattering magnitude |S|^2') + ax_s.set_xlabel('Incident mode index') + ax_s.set_ylabel('Outgoing mode index') + + e_left = unvec(left_mode[0], shape_2d) + e_right = unvec(right_mode[0], shape_2d) + left_intensity = numpy.sum(abs(e_left) ** 2, axis=0).T + right_intensity = numpy.sum(abs(e_right) ** 2, axis=0).T + + fig_modes, axes = pyplot.subplots(1, 2, figsize=(10, 4)) + left_plot = axes[0].imshow(left_intensity, origin='lower', cmap='viridis') + fig_modes.colorbar(left_plot, ax=axes[0]) + axes[0].set_title('Left fundamental mode |E|^2') + right_plot = axes[1].imshow(right_intensity, origin='lower', cmap='viridis') + fig_modes.colorbar(right_plot, ax=axes[1]) + axes[1].set_title('Right fundamental mode |E|^2') + if pyplot.get_backend().lower().endswith('agg'): + pyplot.close(fig_s) + pyplot.close(fig_modes) + else: + pyplot.show() + + +def main() -> None: + pyplot = require_optional('matplotlib.pyplot', package_name='matplotlib') + + grid, epsilon, dxes_2d, omega = build_geometry() + left_slice = epsilon[:, :, :, 1] + right_slice = epsilon[:, :, :, -2] + + left_modes, wavenumbers_left = solve_cross_section_modes(left_slice, omega=omega, dxes_2d=dxes_2d) + right_modes, wavenumbers_right = solve_cross_section_modes(right_slice, omega=omega, dxes_2d=dxes_2d) + + ss = eme.get_s(left_modes, wavenumbers_left, right_modes, wavenumbers_right, dxes=dxes_2d) + + print_summary(ss, wavenumbers_left, wavenumbers_right, omega) + plot_results( + pyplot=pyplot, + ss=ss, + left_mode=left_modes[0], + right_mode=right_modes[0], + shape_2d=grid.shape[:2], + ) + + +if __name__ == '__main__': + main() diff --git a/examples/eme_bend.py b/examples/eme_bend.py new file mode 100644 index 0000000..e5eaebd --- /dev/null +++ b/examples/eme_bend.py @@ -0,0 +1,314 @@ +""" +Mode-matching / EME example for a straight-to-bent waveguide interface. + +This example demonstrates a cylindrical-waveguide EME workflow: + +1. build a rib-waveguide cross-section, +2. solve straight port modes with `waveguide_2d`, +3. solve bend modes with `waveguide_cyl`, +4. assemble the straight-to-bend interface scattering matrix with + `meanas.fdfd.eme.get_s(...)`, +5. optionally cascade a straight section, bend section, and interface pair into + a compact multiport network using `scikit-rf`. +""" + +from __future__ import annotations + +import importlib +from typing import TYPE_CHECKING + +import numpy +from numpy import pi +from scipy import sparse + +import gridlock +from gridlock import Extent + +from meanas.fdfd import eme, waveguide_2d, waveguide_cyl +from meanas.fdmath import unvec + +if TYPE_CHECKING: + from types import ModuleType + + +WL = 1310.0 +DX = 40.0 +RADIUS = 6e3 +WIDTH = 400.0 +THF = 161.0 +THP = 77.0 +EPS_SI = 3.51 ** 2 +EPS_OX = 1.453 ** 2 +MODE_NUMBERS = numpy.array([0]) +STRAIGHT_SECTION_LENGTH = 12e3 +BEND_ANGLE = pi / 2 + + +def require_optional(name: str, package_name: str | None = None) -> ModuleType: + package_name = package_name or name + try: + return importlib.import_module(name) + except ImportError as exc: # pragma: no cover - user environment guard + raise SystemExit( + f"This example requires the optional package '{package_name}'. " + "Install example dependencies with `pip install -e './meanas[examples]'`.", + ) from exc + + +def build_geometry( + *, + dx: float = DX, + width: float = WIDTH, + thf: float = THF, + thp: float = THP, + eps_si: float = EPS_SI, + eps_ox: float = EPS_OX, + ) -> tuple[gridlock.Grid, numpy.ndarray, list[list[numpy.ndarray]], float]: + x0 = (width / 2) % dx + omega = 2 * pi / WL + + grid = gridlock.Grid( + [ + numpy.arange(-800, 800 + dx, dx), + numpy.arange(-400, 400 + dx, dx), + numpy.arange(-2 * dx, 2 * dx + dx, dx), + ], + periodic=True, + ) + epsilon = grid.allocate(eps_ox) + + grid.draw_cuboid( + epsilon, + foreground=eps_si, + x=Extent(center=x0, span=width + 1200), + y=Extent(min=0, max=thf), + z=Extent(min=-1e6, max=0), + ) + grid.draw_cuboid( + epsilon, + foreground=eps_ox, + x=Extent(max=-width / 2, span=300), + y=Extent(min=thp, max=1e6), + z=Extent(min=-1e6, center=0), + ) + grid.draw_cuboid( + epsilon, + foreground=eps_ox, + x=Extent(min=width / 2, span=300), + y=Extent(min=thp, max=1e6), + z=Extent(min=-1e6, center=0), + ) + + dxes = [grid.dxyz, grid.autoshifted_dxyz()] + dxes_2d = [[d[0], d[1]] for d in dxes] + return grid, epsilon, dxes_2d, omega + + +def solve_straight_modes( + epsilon_slice: numpy.ndarray, + *, + omega: float, + dxes_2d: list[list[numpy.ndarray]], + mode_numbers: numpy.ndarray = MODE_NUMBERS, + ) -> tuple[list[tuple[numpy.ndarray, numpy.ndarray]], numpy.ndarray]: + e_xys, wavenumbers = waveguide_2d.solve_modes( + epsilon=epsilon_slice.ravel(), + omega=omega, + dxes=dxes_2d, + mode_numbers=mode_numbers, + ) + eh_fields = [ + waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + dxes=dxes_2d, + omega=omega, + epsilon=epsilon_slice.ravel(), + ) + for e_xy, wavenumber in zip(e_xys, wavenumbers, strict=True) + ] + return eh_fields, wavenumbers + + +def solve_bend_modes( + epsilon_slice: numpy.ndarray, + *, + omega: float, + dxes_2d: list[list[numpy.ndarray]], + rmin: float, + mode_numbers: numpy.ndarray = MODE_NUMBERS, + ) -> tuple[list[tuple[numpy.ndarray, numpy.ndarray]], numpy.ndarray, numpy.ndarray]: + e_xys, angular_wavenumbers = waveguide_cyl.solve_modes( + epsilon=epsilon_slice.ravel(), + omega=omega, + dxes=dxes_2d, + mode_numbers=mode_numbers, + rmin=rmin, + ) + linear_wavenumbers = waveguide_cyl.linear_wavenumbers( + e_xys=e_xys, + angular_wavenumbers=angular_wavenumbers, + rmin=rmin, + epsilon=epsilon_slice.ravel(), + dxes=dxes_2d, + ) + eh_fields = [ + waveguide_cyl.normalized_fields_e( + e_xy, + angular_wavenumber=angular_wavenumber, + dxes=dxes_2d, + omega=omega, + epsilon=epsilon_slice.ravel(), + rmin=rmin, + ) + for e_xy, angular_wavenumber in zip(e_xys, angular_wavenumbers, strict=True) + ] + return eh_fields, linear_wavenumbers, angular_wavenumbers + + +def build_cascaded_network( + skrf: ModuleType, + *, + interface_s: numpy.ndarray, + straight_wavenumbers: numpy.ndarray, + bend_angular_wavenumbers: numpy.ndarray, + n_modes: int, + ) -> object: + net_sb = skrf.Network(f=[1 / WL], s=interface_s[numpy.newaxis, ...]) + net_bs = net_sb.copy() + net_bs.renumber(numpy.arange(2 * n_modes), numpy.roll(numpy.arange(2 * n_modes), n_modes)) + + straight_phase = sparse.diags_array(numpy.exp(-1j * straight_wavenumbers[:n_modes] * STRAIGHT_SECTION_LENGTH)) + bend_phase = sparse.diags_array(numpy.exp(-1j * bend_angular_wavenumbers[:n_modes] * BEND_ANGLE)) + zero = numpy.zeros((n_modes, n_modes), dtype=complex) + + straight_s = numpy.block([[zero, straight_phase.toarray()], [straight_phase.toarray(), zero]]) + bend_s = numpy.block([[zero, bend_phase.toarray()], [bend_phase.toarray(), zero]]) + net_straight = skrf.Network(f=[1 / WL], s=straight_s[numpy.newaxis, ...]) + net_bend = skrf.Network(f=[1 / WL], s=bend_s[numpy.newaxis, ...]) + + return skrf.network.cascade_list([net_straight, net_sb, net_bend, net_bs, net_straight]) + + +def print_summary( + interface_s: numpy.ndarray, + cascaded_s: numpy.ndarray, + straight_wavenumbers: numpy.ndarray, + bend_linear_wavenumbers: numpy.ndarray, + bend_angular_wavenumbers: numpy.ndarray, + omega: float, + n_modes: int, + ) -> None: + straight_neff = numpy.real(straight_wavenumbers / omega) + bend_neff = numpy.real(bend_linear_wavenumbers / omega) + print('straight effective indices:', ', '.join(f'{value:.5f}' for value in straight_neff[:4])) + print('bend effective indices :', ', '.join(f'{value:.5f}' for value in bend_neff[:4])) + print('bend angular wavenumbers :', ', '.join(f'{value:.5e}' for value in bend_angular_wavenumbers[:4])) + + interface_transmission = abs(interface_s[n_modes, 0]) ** 2 + interface_reflection = abs(interface_s[0, 0]) ** 2 + print(f'interface fundamental transmission |S_{n_modes},0|^2 = {interface_transmission:.6f}') + print(f'interface fundamental reflection |S_00|^2 = {interface_reflection:.6f}') + + total_cascaded_output = numpy.sum(abs(cascaded_s[:, 0]) ** 2) + bend_through = abs(cascaded_s[n_modes, 0]) ** 2 + bend_reflection = abs(cascaded_s[0, 0]) ** 2 + print(f'cascaded bend through power |S_{n_modes},0|^2 = {bend_through:.6f}') + print(f'cascaded bend reflection |S_00|^2 = {bend_reflection:.6f}') + print(f'cascaded left-incident total output power = {total_cascaded_output:.6f}') + + +def plot_results( + *, + pyplot: ModuleType, + interface_s: numpy.ndarray, + cascaded_s: numpy.ndarray, + straight_mode: tuple[numpy.ndarray, numpy.ndarray], + bend_mode: tuple[numpy.ndarray, numpy.ndarray], + shape_2d: tuple[int, int], + ) -> None: + fig_s, axes = pyplot.subplots(1, 2, figsize=(12, 4)) + interface_plot = axes[0].imshow(abs(interface_s) ** 2, origin='lower', cmap='magma') + fig_s.colorbar(interface_plot, ax=axes[0]) + axes[0].set_title('Straight-to-bend interface |S|^2') + axes[0].set_xlabel('Incident mode index') + axes[0].set_ylabel('Outgoing mode index') + + cascaded_plot = axes[1].imshow(abs(cascaded_s) ** 2, origin='lower', cmap='magma') + fig_s.colorbar(cascaded_plot, ax=axes[1]) + axes[1].set_title('Cascaded bend network |S|^2') + axes[1].set_xlabel('Incident mode index') + axes[1].set_ylabel('Outgoing mode index') + + straight_e = unvec(straight_mode[0], shape_2d) + bend_e = unvec(bend_mode[0], shape_2d) + straight_intensity = numpy.sum(abs(straight_e) ** 2, axis=0).T + bend_intensity = numpy.sum(abs(bend_e) ** 2, axis=0).T + + fig_modes, axes_modes = pyplot.subplots(1, 2, figsize=(10, 4)) + straight_plot = axes_modes[0].imshow(straight_intensity, origin='lower', cmap='viridis') + fig_modes.colorbar(straight_plot, ax=axes_modes[0]) + axes_modes[0].set_title('Straight fundamental mode |E|^2') + bend_plot = axes_modes[1].imshow(bend_intensity, origin='lower', cmap='viridis') + fig_modes.colorbar(bend_plot, ax=axes_modes[1]) + axes_modes[1].set_title('Bent fundamental mode |E|^2') + if pyplot.get_backend().lower().endswith('agg'): + pyplot.close(fig_s) + pyplot.close(fig_modes) + else: + pyplot.show() + + +def main() -> None: + pyplot = require_optional('matplotlib.pyplot', package_name='matplotlib') + skrf = require_optional('skrf', package_name='scikit-rf') + + grid, epsilon, dxes_2d, omega = build_geometry() + epsilon_slice = epsilon[:, :, :, 2] + rmin = RADIUS + grid.xyz[0].min() + + straight_modes, straight_wavenumbers = solve_straight_modes(epsilon_slice, omega=omega, dxes_2d=dxes_2d) + bend_modes, bend_linear_wavenumbers, bend_angular_wavenumbers = solve_bend_modes( + epsilon_slice, + omega=omega, + dxes_2d=dxes_2d, + rmin=rmin, + ) + + interface_s = eme.get_s( + straight_modes, + straight_wavenumbers, + bend_modes, + bend_linear_wavenumbers, + dxes=dxes_2d, + ) + cascaded = build_cascaded_network( + skrf, + interface_s=interface_s, + straight_wavenumbers=straight_wavenumbers, + bend_angular_wavenumbers=bend_angular_wavenumbers, + n_modes=len(MODE_NUMBERS), + ) + cascaded_s = cascaded.s[0] + + print_summary( + interface_s, + cascaded_s, + straight_wavenumbers, + bend_linear_wavenumbers, + bend_angular_wavenumbers, + omega, + len(MODE_NUMBERS), + ) + plot_results( + pyplot=pyplot, + interface_s=interface_s, + cascaded_s=cascaded_s, + straight_mode=straight_modes[0], + bend_mode=bend_modes[0], + shape_2d=grid.shape[:2], + ) + + +if __name__ == '__main__': + main() diff --git a/examples/fdfd0.py b/examples/fdfd0.py new file mode 100644 index 0000000..a6227c5 --- /dev/null +++ b/examples/fdfd0.py @@ -0,0 +1,103 @@ +import numpy +from numpy.linalg import norm +from matplotlib import pyplot, colors +import logging + +import meanas +from meanas import fdtd +from meanas.fdmath import vec, unvec +from meanas.fdfd import waveguide_3d, functional, scpml, operators +from meanas.fdfd.solvers import generic as generic_solver + +import gridlock + + +logging.basicConfig(level=logging.DEBUG) +logging.getLogger('matplotlib').setLevel(logging.WARNING) + +__author__ = 'Jan Petykiewicz' + + +def pcolor(ax, v) -> None: + mappable = ax.pcolor(v, cmap='seismic', norm=colors.CenteredNorm()) + ax.axis('equal') + ax.get_figure().colorbar(mappable) + + +def test0(solver=generic_solver): + dx = 50 # discretization (nm/cell) + pml_thickness = 10 # (number of cells) + + wl = 1550 # Excitation wavelength + omega = 2 * numpy.pi / wl + + # Device design parameters + radii = (1, 0.6) + th = 220 + center = [0, 0, 0] + + # refractive indices + n_ring = numpy.sqrt(12.6) # ~Si + n_air = 4.0 # air + + # Half-dimensions of the simulation grid + xyz_max = numpy.array([1.2, 1.2, 0.3]) * 1000 + pml_thickness * dx + + # Coordinates of the edges of the cells. + half_edge_coords = [numpy.arange(dx/2, m + dx, step=dx) for m in xyz_max] + edge_coords = [numpy.hstack((-h[::-1], h)) for h in half_edge_coords] + + # #### Create the grid, mask, and draw the device #### + grid = gridlock.Grid(edge_coords) + epsilon = grid.allocate(n_air**2, dtype=numpy.float32) + grid.draw_cylinder( + epsilon, + h = dict(axis='z', center=center[2], span=th), + radius = max(radii), + center2d = center[:2], + foreground = n_ring ** 2, + num_points = 24, + ) + grid.draw_cylinder( + epsilon, + h = dict(axis='z', center=center[2], span=th * 1.1), + radius = min(radii), + center2d = center[:2], + foreground = n_air ** 2, + num_points = 24, + ) + + dxes = [grid.dxyz, grid.autoshifted_dxyz()] + for a in (0, 1, 2): + for p in (-1, 1): + dxes = meanas.fdfd.scpml.stretch_with_scpml(dxes, axis=a, polarity=p, omega=omega, + thickness=pml_thickness) + + J = [numpy.zeros_like(epsilon[0], dtype=complex) for _ in range(3)] + J[1][15, grid.shape[1]//2, grid.shape[2]//2] = 1 + + + # + # Solve! + # + sim_args = dict( + omega = omega, + dxes = dxes, + epsilon = vec(epsilon), + ) + x = solver(J=vec(J), **sim_args) + + A = operators.e_full(omega, dxes, vec(epsilon)).tocsr() + b = -1j * omega * vec(J) + print('Norm of the residual is ', norm(A @ x - b) / norm(b)) + + E = unvec(x, grid.shape) + + # + # Plot results + # + grid.visualize_slice(E.real, plane=dict(z=0), which_shifts=1, pcolormesh_args=dict(norm=colors.CenteredNorm(), cmap='bwr')) + + +if __name__ == '__main__': + test0() diff --git a/examples/fdfd.py b/examples/fdfd1.py similarity index 52% rename from examples/fdfd.py rename to examples/fdfd1.py index 4612ba0..f983d37 100644 --- a/examples/fdfd.py +++ b/examples/fdfd1.py @@ -1,10 +1,13 @@ import importlib +import logging import numpy from numpy.linalg import norm +from matplotlib import pyplot, colors +import logging import meanas from meanas import fdtd -from meanas.fdmath import vec, unvec +from meanas.fdmath import vec, unvec, fdfield_t from meanas.fdfd import waveguide_3d, functional, scpml, operators from meanas.fdfd.solvers import generic as generic_solver @@ -12,7 +15,6 @@ import gridlock from matplotlib import pyplot -import logging logging.basicConfig(level=logging.DEBUG) logging.getLogger('matplotlib').setLevel(logging.WARNING) @@ -20,82 +22,6 @@ logging.getLogger('matplotlib').setLevel(logging.WARNING) __author__ = 'Jan Petykiewicz' -def test0(solver=generic_solver): - dx = 50 # discretization (nm/cell) - pml_thickness = 10 # (number of cells) - - wl = 1550 # Excitation wavelength - omega = 2 * numpy.pi / wl - - # Device design parameters - radii = (1, 0.6) - th = 220 - center = [0, 0, 0] - - # refractive indices - n_ring = numpy.sqrt(12.6) # ~Si - n_air = 4.0 # air - - # Half-dimensions of the simulation grid - xyz_max = numpy.array([1.2, 1.2, 0.3]) * 1000 + pml_thickness * dx - - # Coordinates of the edges of the cells. - half_edge_coords = [numpy.arange(dx/2, m + dx, step=dx) for m in xyz_max] - edge_coords = [numpy.hstack((-h[::-1], h)) for h in half_edge_coords] - - # #### Create the grid, mask, and draw the device #### - grid = gridlock.Grid(edge_coords) - epsilon = grid.allocate(n_air**2, dtype=numpy.float32) - grid.draw_cylinder(epsilon, - surface_normal=2, - center=center, - radius=max(radii), - thickness=th, - eps=n_ring**2, - num_points=24) - grid.draw_cylinder(epsilon, - surface_normal=2, - center=center, - radius=min(radii), - thickness=th*1.1, - eps=n_air ** 2, - num_points=24) - - dxes = [grid.dxyz, grid.autoshifted_dxyz()] - for a in (0, 1, 2): - for p in (-1, 1): - dxes = meanas.fdfd.scpml.stretch_with_scpml(dxes, axis=a, polarity=p, omega=omega, - thickness=pml_thickness) - - J = [numpy.zeros_like(epsilon[0], dtype=complex) for _ in range(3)] - J[1][15, grid.shape[1]//2, grid.shape[2]//2] = 1 - - - ''' - Solve! - ''' - sim_args = { - 'omega': omega, - 'dxes': dxes, - 'epsilon': vec(epsilon), - } - x = solver(J=vec(J), **sim_args) - - A = operators.e_full(omega, dxes, vec(epsilon)).tocsr() - b = -1j * omega * vec(J) - print('Norm of the residual is ', norm(A @ x - b)) - - E = unvec(x, grid.shape) - - ''' - Plot results - ''' - pyplot.figure() - pyplot.pcolor(numpy.real(E[1][:, :, grid.shape[2]//2]), cmap='seismic') - pyplot.axis('equal') - pyplot.show() - - def test1(solver=generic_solver): dx = 40 # discretization (nm/cell) pml_thickness = 10 # (number of cells) @@ -122,7 +48,7 @@ def test1(solver=generic_solver): # #### Create the grid and draw the device #### grid = gridlock.Grid(edge_coords) epsilon = grid.allocate(n_air**2, dtype=numpy.float32) - grid.draw_cuboid(epsilon, center=center, dimensions=[8e3, w, th], eps=n_wg**2) + grid.draw_cuboid(epsilon, x=dict(center=0, span=8e3), y=dict(center=0, span=w), z=dict(center=0, span=th), foreground=n_wg**2) dxes = [grid.dxyz, grid.autoshifted_dxyz()] for a in (0, 1, 2): @@ -156,22 +82,14 @@ def test1(solver=generic_solver): # grid.draw_cuboid(pmcg, center=[700, 0, 0], dimensions=[80, 1e8, 1e8], eps=1) # grid.visualize_isosurface(pmcg) - def pcolor(v) -> None: - vmax = numpy.max(numpy.abs(v)) - pyplot.pcolor(v, cmap='seismic', vmin=-vmax, vmax=vmax) - pyplot.axis('equal') - pyplot.colorbar() - - ss = (1, slice(None), J.shape[2]//2+6, slice(None)) -# pyplot.figure() -# pcolor(J3[ss].T.imag) -# pyplot.figure() -# pcolor((numpy.abs(J3).sum(axis=2).sum(axis=0) > 0).astype(float).T) + grid.visualize_slice(J.imag, plane=dict(y=6*dx), which_shifts=1, pcolormesh_args=dict(norm=colors.CenteredNorm(), cmap='bwr')) + fig, ax = pyplot.subplots() + ax.pcolormesh((numpy.abs(J).sum(axis=2).sum(axis=0) > 0).astype(float).T, cmap='hot') pyplot.show(block=True) - ''' - Solve! - ''' + # + # Solve! + # sim_args = { 'omega': omega, 'dxes': dxes, @@ -188,20 +106,18 @@ def test1(solver=generic_solver): E = unvec(x, grid.shape) - ''' - Plot results - ''' + # + # Plot results + # center = grid.pos2ind([0, 0, 0], None).astype(int) - pyplot.figure() - pyplot.subplot(2, 2, 1) - pcolor(numpy.real(E[1][center[0], :, :]).T) - pyplot.subplot(2, 2, 2) - pyplot.plot(numpy.log10(numpy.abs(E[1][:, center[1], center[2]]) + 1e-10)) - pyplot.grid(alpha=0.6) - pyplot.ylabel('log10 of field') - pyplot.subplot(2, 2, 3) - pcolor(numpy.real(E[1][:, :, center[2]]).T) - pyplot.subplot(2, 2, 4) + fig, axes = pyplot.subplots(2, 2) + grid.visualize_slice(E.real, plane=dict(x=0), which_shifts=1, ax=axes[0, 0], finalize=False, pcolormesh_args=dict(norm=colors.CenteredNorm(), cmap='bwr')) + grid.visualize_slice(E.real, plane=dict(z=0), which_shifts=1, ax=axes[0, 1], finalize=False, pcolormesh_args=dict(norm=colors.CenteredNorm(), cmap='bwr')) +# pcolor(axes[0, 0], numpy.real(E[1][center[0], :, :]).T) +# pcolor(axes[0, 1], numpy.real(E[1][:, :, center[2]]).T) + axes[1, 0].plot(numpy.log10(numpy.abs(E[1][:, center[1], center[2]]) + 1e-10)) + axes[1, 0].grid(alpha=0.6) + axes[1, 0].set_ylabel('log10 of field') def poyntings(E): H = functional.e2h(omega, dxes)(E) @@ -215,24 +131,28 @@ def test1(solver=generic_solver): return s0, s1, s2 s0x, s1x, s2x = poyntings(E) - pyplot.plot(s0x[0].sum(axis=2).sum(axis=1), label='s0', marker='.') - pyplot.plot(s1x[0].sum(axis=2).sum(axis=1), label='s1', marker='.') - pyplot.plot(s2x[0].sum(axis=2).sum(axis=1), label='s2', marker='.') - pyplot.plot(E[1][:, center[1], center[2]].real.T, label='Ey', marker='x') - pyplot.grid(alpha=0.6) - pyplot.legend() - pyplot.show() + ax = axes[1, 1] + ax.plot(s0x[0].sum(axis=2).sum(axis=1), label='s0', marker='.') + ax.plot(s1x[0].sum(axis=2).sum(axis=1), label='s1', marker='.') + ax.plot(s2x[0].sum(axis=2).sum(axis=1), label='s2', marker='.') + ax.plot(E[1][:, center[1], center[2]].real.T, label='Ey', marker='x') + ax.grid(alpha=0.6) + ax.legend() + + p_in = (-E * J.conj()).sum() / 2 * (dx * dx * dx) + print(f'{p_in=}') q = [] for i in range(-5, 30): e_ovl_rolled = numpy.roll(e_overlap, i, axis=1) - q += [numpy.abs(vec(E) @ vec(e_ovl_rolled).conj())] - pyplot.figure() - pyplot.plot(q, marker='.') - pyplot.grid(alpha=0.6) - pyplot.title('Overlap with mode') - pyplot.show() - print('Average overlap with mode:', sum(q)/len(q)) + q += [numpy.abs(vec(E).conj() @ vec(e_ovl_rolled))] + fig, ax = pyplot.subplots() + ax.plot(q, marker='.') + ax.grid(alpha=0.6) + ax.set_title('Overlap with mode') + print('Average overlap with mode:', sum(q[8:32])/len(q[8:32])) + + pyplot.show(block=True) def module_available(name): @@ -240,9 +160,6 @@ def module_available(name): if __name__ == '__main__': - #test0() -# test1() - if module_available('opencl_fdfd'): from opencl_fdfd import cg_solver as opencl_solver test1(opencl_solver) @@ -253,3 +170,4 @@ if __name__ == '__main__': # test1(magma_solver) else: test1() + diff --git a/examples/fdtd.py b/examples/fdtd.py index 8378b34..fd6026d 100644 --- a/examples/fdtd.py +++ b/examples/fdtd.py @@ -1,18 +1,30 @@ """ -Example code for running an OpenCL FDTD simulation +Example code for a broadband FDTD run with phasor extraction. -See main() for simulation setup. +This script shows the intended low-level workflow for: + +1. building a Yee-grid simulation with CPML on all faces, +2. driving it with an electric-current pulse, +3. extracting a single-frequency phasor on the fly, and +4. checking that phasor against the matching stretched-grid FDFD operator. """ import sys import time +import copy import numpy import h5py +from numpy.linalg import norm from meanas import fdtd from meanas.fdtd import cpml_params, updates_with_cpml -from masque import Pattern, shapes +from meanas.fdtd.misc import gaussian_packet + +from meanas.fdfd.operators import e_full +from meanas.fdfd.scpml import stretch_with_scpml +from meanas.fdmath import vec +from masque import Pattern, Circle, Polygon import gridlock import pcgen @@ -41,50 +53,50 @@ def perturbed_l3(a: float, radius: float, **kwargs) -> Pattern: `masque.Pattern` object containing the L3 design """ - default_args = {'hole_dose': 1, - 'trench_dose': 1, - 'hole_layer': 0, - 'trench_layer': 1, - 'shifts_a': (0.15, 0, 0.075), - 'shifts_r': (1.0, 1.0, 1.0), - 'xy_size': (10, 10), - 'perturbed_radius': 1.1, - 'trench_width': 1.2e3, - } + default_args = { + 'hole_layer': 0, + 'trench_layer': 1, + 'shifts_a': (0.15, 0, 0.075), + 'shifts_r': (1.0, 1.0, 1.0), + 'xy_size': (10, 10), + 'perturbed_radius': 1.1, + 'trench_width': 1.2e3, + } kwargs = {**default_args, **kwargs} - xyr = pcgen.l3_shift_perturbed_defect(mirror_dims=kwargs['xy_size'], - perturbed_radius=kwargs['perturbed_radius'], - shifts_a=kwargs['shifts_a'], - shifts_r=kwargs['shifts_r']) + xyr = pcgen.l3_shift_perturbed_defect( + mirror_dims=kwargs['xy_size'], + perturbed_radius=kwargs['perturbed_radius'], + shifts_a=kwargs['shifts_a'], + shifts_r=kwargs['shifts_r'], + ) xyr *= a xyr[:, 2] *= radius pat = Pattern() - pat.name = f'L3p-a{a:g}r{radius:g}rp{kwargs["perturbed_radius"]:g}' - pat.shapes += [shapes.Circle(radius=r, offset=(x, y), - dose=kwargs['hole_dose'], - layer=kwargs['hole_layer']) - for x, y, r in xyr] + #pat.name = f'L3p-a{a:g}r{radius:g}rp{kwargs["perturbed_radius"]:g}' + pat.shapes[(kwargs['hole_layer'], 0)] += [ + Circle(radius=r, offset=(x, y)) + for x, y, r in xyr] maxes = numpy.max(numpy.fabs(xyr), axis=0) - pat.shapes += [shapes.Polygon.rectangle( - lx=(2 * maxes[0]), ly=kwargs['trench_width'], - offset=(0, s * (maxes[1] + a + kwargs['trench_width'] / 2)), - dose=kwargs['trench_dose'], layer=kwargs['trench_layer']) - for s in (-1, 1)] + pat.shapes[(kwargs['trench_layer'], 0)] += [ + Polygon.rectangle( + lx=(2 * maxes[0]), ly=kwargs['trench_width'], + offset=(0, s * (maxes[1] + a + kwargs['trench_width'] / 2)) + ) + for s in (-1, 1)] return pat -def main(): +def main() -> None: dtype = numpy.float32 - max_t = 8000 # number of timesteps + max_t = 3600 # number of timesteps dx = 40 # discretization (nm/cell) pml_thickness = 8 # (number of cells) wl = 1550 # Excitation wavelength and fwhm - dwl = 200 # Device design parameters xy_size = numpy.array([10, 10]) @@ -107,69 +119,97 @@ def main(): # #### Create the grid, mask, and draw the device #### grid = gridlock.Grid(edge_coords) - epsilon = grid.allocate(n_air**2, dtype=dtype) - grid.draw_slab(epsilon, - surface_normal=2, - center=[0, 0, 0], - thickness=th, - eps=n_slab**2) + epsilon = grid.allocate(n_air ** 2, dtype=dtype) + grid.draw_slab( + epsilon, + slab = dict(axis='z', center=0, span=th), + foreground = n_slab ** 2, + ) + mask = perturbed_l3(a, r) + grid.draw_polygons( + epsilon, + slab = dict(axis='z', center=0, span=2 * th), + foreground = n_air ** 2, + offset2d = (0, 0), + polygons = mask.as_polygons(library=None), + ) - grid.draw_polygons(epsilon, - surface_normal=2, - center=[0, 0, 0], - thickness=2 * th, - eps=n_air**2, - polygons=mask.as_polygons()) + print(f'{grid.shape=}') - print(grid.shape) - - dt = .99/numpy.sqrt(3) - e = [numpy.zeros_like(epsilon[0], dtype=dtype) for _ in range(3)] - h = [numpy.zeros_like(epsilon[0], dtype=dtype) for _ in range(3)] + dt = dx * 0.99 / numpy.sqrt(3) + ee = numpy.zeros_like(epsilon, dtype=complex) + hh = numpy.zeros_like(epsilon, dtype=complex) dxes = [grid.dxyz, grid.autoshifted_dxyz()] # PMLs in every direction - pml_params = [[cpml_params(axis=dd, polarity=pp, dt=dt, - thickness=pml_thickness, epsilon_eff=1.0**2) - for pp in (-1, +1)] - for dd in range(3)] - update_E, update_H = updates_with_cpml(cpml_params=pml_params, dt=dt, - dxes=dxes, epsilon=epsilon) + pml_params = [ + [cpml_params(axis=dd, polarity=pp, dt=dt, thickness=pml_thickness, epsilon_eff=n_air ** 2) + for pp in (-1, +1)] + for dd in range(3)] + update_E, update_H = updates_with_cpml(cpml_params=pml_params, dt=dt, dxes=dxes, epsilon=epsilon, dtype=complex) - # Source parameters and function - w = 2 * numpy.pi * dx / wl - fwhm = dwl * w * w / (2 * numpy.pi * dx) - alpha = (fwhm ** 2) / 8 * numpy.log(2) - delay = 7/numpy.sqrt(2 * alpha) + # sample_interval = numpy.floor(1 / (2 * 1 / wl * dt)).astype(int) + # print(f'Save time interval would be {sample_interval} * dt = {sample_interval * dt:3g}') - def field_source(i): - t0 = i * dt - delay - return numpy.sin(w * t0) * numpy.exp(-alpha * t0**2) + + # Build the pulse directly at the current half-steps and normalize that + # scalar waveform so its extracted temporal phasor is exactly 1 at omega. + source_phasor, _delay = gaussian_packet(wl=wl, dwl=100, dt=dt, turn_on=1e-5) + aa, cc, ss = source_phasor(numpy.arange(max_t) + 0.5) + source_waveform = aa * (cc + 1j * ss) + omega = 2 * numpy.pi / wl + pulse_scale = fdtd.temporal_phasor_scale(source_waveform, omega, dt, offset_steps=0.5)[0] + + j_source = numpy.zeros_like(epsilon, dtype=complex) + j_source[1, *(grid.shape // 2)] = epsilon[1, *(grid.shape // 2)] + jph = numpy.zeros((1, *epsilon.shape), dtype=complex) + eph = numpy.zeros((1, *epsilon.shape), dtype=complex) + hph = numpy.zeros((1, *epsilon.shape), dtype=complex) # #### Run a bunch of iterations #### output_file = h5py.File('simulation_output.h5', 'w') start = time.perf_counter() - for t in range(max_t): - update_E(e, h, epsilon) + for tt in range(max_t): + update_E(ee, hh, epsilon) - e[1][tuple(grid.shape//2)] += field_source(t) - update_H(e, h) + # Electric-current injection uses E -= dt * J / epsilon, which is the + # same sign convention used by the matching FDFD right-hand side. + j_step = pulse_scale * source_waveform[tt] * j_source + ee -= dt * j_step / epsilon + update_H(ee, hh) - avg_rate = (t + 1)/(time.perf_counter() - start)) - print(f'iteration {t}: average {avg_rate} iterations per sec') + avg_rate = (tt + 1) / (time.perf_counter() - start) sys.stdout.flush() - if t % 20 == 0: - r = sum([(f * f * e).sum() for f, e in zip(e, epsilon)]) - print('E sum', r) + if tt % 200 == 0: + print(f'iteration {tt}: average {avg_rate} iterations per sec') + E_energy_sum = (ee.conj() * ee * epsilon).sum().real + print(f'{E_energy_sum=}') # Save field slices - if (t % 20 == 0 and (max_t - t <= 1000 or t <= 2000)) or t == max_t-1: - print('saving E-field') - for j, f in enumerate(e): - output_file['/E{}_t{}'.format('xyz'[j], t)] = f[:, :, round(f.shape[2]/2)] + if (tt % 20 == 0 and (max_t - tt <= 1000 or tt <= 2000)) or tt == max_t - 1: + print(f'saving E-field at iteration {tt}') + output_file[f'/E_t{tt}'] = ee[:, :, :, ee.shape[3] // 2] + + fdtd.accumulate_phasor_j(jph, omega, dt, j_step, tt) + fdtd.accumulate_phasor_e(eph, omega, dt, ee, tt + 1) + fdtd.accumulate_phasor_h(hph, omega, dt, hh, tt + 1) + + Eph = eph[0] + Jph = jph[0] + b = -1j * omega * Jph + dxes_fdfd = copy.deepcopy(dxes) + for pp in (-1, +1): + for dd in range(3): + stretch_with_scpml(dxes_fdfd, axis=dd, polarity=pp, omega=omega, epsilon_effective=n_air ** 2, thickness=pml_thickness) + # Compare the extracted phasor to the FDFD operator on the stretched grid, + # not the unstretched Yee spacings used by the raw time-domain update. + A = e_full(omega=omega, dxes=dxes_fdfd, epsilon=epsilon) + residual = norm(A @ vec(Eph) - vec(b)) / norm(vec(b)) + print(f'FDFD residual is {residual}') + if __name__ == '__main__': main() diff --git a/examples/waveguide.py b/examples/waveguide.py new file mode 100644 index 0000000..f243924 --- /dev/null +++ b/examples/waveguide.py @@ -0,0 +1,342 @@ +""" +Example code for guided-wave FDFD and FDTD comparison. + +This example is the reference workflow for: + +1. solving a waveguide port mode, +2. turning that mode into a one-sided source and overlap window, +3. comparing a direct FDFD solve against a time-domain phasor extracted from FDTD. +""" +from typing import Callable +import logging +import time +import copy + +import numpy +import h5py +from numpy.linalg import norm + +import gridlock +import meanas +from meanas import fdtd, fdfd +from meanas.fdtd import cpml_params, updates_with_cpml +from meanas.fdtd.misc import gaussian_packet + +from meanas.fdmath import vec, unvec, vcfdfield_t, cfdfield_t, fdfield_t, dx_lists_t +from meanas.fdfd import waveguide_3d, functional, scpml, operators +from meanas.fdfd.solvers import generic as generic_solver +from meanas.fdfd.operators import e_full +from meanas.fdfd.scpml import stretch_with_scpml + + +logging.basicConfig(level=logging.DEBUG) +for pp in ('matplotlib', 'PIL'): + logging.getLogger(pp).setLevel(logging.WARNING) + +logger = logging.getLogger(__name__) + + +def pcolor(vv, fig=None, ax=None) -> None: + if fig is None: + assert ax is None + fig, ax = pyplot.subplots() + mb = ax.pcolor(vv, cmap='seismic', norm=colors.CenteredNorm()) + fig.colorbar(mb) + ax.set_aspect('equal') + + +def draw_grid( + *, + dx: float, + pml_thickness: int, + n_wg: float = 3.476, # Si index @ 1550 + n_cladding: float = 1.00, # Air index + wg_w: float = 400, + wg_th: float = 200, + ) -> tuple[gridlock.Grid, fdfield_t]: + """ Create the grid and draw the device """ + # Half-dimensions of the simulation grid + xyz_max = numpy.array([800, 900, 600]) + (pml_thickness + 2) * dx + + # Coordinates of the edges of the cells. + half_edge_coords = [numpy.arange(dx / 2, m + dx / 2, step=dx) for m in xyz_max] + edge_coords = [numpy.hstack((-h[::-1], h)) for h in half_edge_coords] + + grid = gridlock.Grid(edge_coords) + epsilon = grid.allocate(n_cladding**2, dtype=numpy.float32) + grid.draw_cuboid( + epsilon, + x = dict(center=0, span=8e3), + y = dict(center=0, span=wg_w), + z = dict(center=0, span=wg_th), + foreground = n_wg ** 2, + ) + + return grid, epsilon + + +def get_waveguide_mode( + *, + grid: gridlock.Grid, + dxes: dx_lists_t, + omega: float, + epsilon: fdfield_t, + ) -> tuple[vcfdfield_t, vcfdfield_t]: + """Create a mode source and overlap window for one forward-going port.""" + dims = numpy.array([[-10, -20, -15], + [-10, 20, 15]]) * [[numpy.median(numpy.real(dx)) for dx in dxes[0]]] + ind_dims = (grid.pos2ind(dims[0], which_shifts=None).astype(int), + grid.pos2ind(dims[1], which_shifts=None).astype(int)) + wg_args = dict( + slices = [slice(i, f+1) for i, f in zip(*ind_dims)], + dxes = dxes, + axis = 0, + polarity = +1, + ) + + wg_results = waveguide_3d.solve_mode(mode_number=0, omega=omega, epsilon=epsilon, **wg_args) + J = waveguide_3d.compute_source(E=wg_results['E'], wavenumber=wg_results['wavenumber'], + omega=omega, epsilon=epsilon, **wg_args) + + # compute_overlap_e() returns the normalized upstream overlap window used to + # project another field onto this same guided mode. + e_overlap = waveguide_3d.compute_overlap_e(E=wg_results['E'], wavenumber=wg_results['wavenumber'], **wg_args) + return J, e_overlap + + +def main( + *, + solver: Callable = generic_solver, + dx: float = 40, # discretization (nm / cell) + pml_thickness: int = 10, # (number of cells) + wl: float = 1550, # Excitation wavelength + wg_w: float = 600, # Waveguide width + wg_th: float = 220, # Waveguide thickness + ): + omega = 2 * numpy.pi / wl + + grid, epsilon = draw_grid(dx=dx, pml_thickness=pml_thickness) + + # Add SCPML stretching to the FDFD grid; this matches the CPML-backed FDTD + # run below so the two solvers see the same absorbing boundary profile. + dxes = [grid.dxyz, grid.autoshifted_dxyz()] + for a in (0, 1, 2): + for p in (-1, 1): + dxes = scpml.stretch_with_scpml(dxes, omega=omega, axis=a, polarity=p, thickness=pml_thickness) + + + J, e_overlap = get_waveguide_mode(grid=grid, dxes=dxes, omega=omega, epsilon=epsilon) + + + pecg = numpy.zeros_like(epsilon) + # pecg.draw_cuboid(pecg, center=[700, 0, 0], dimensions=[80, 1e8, 1e8], eps=1) + # pecg.visualize_isosurface(pecg) + + pmcg = numpy.zeros_like(epsilon) + # grid.draw_cuboid(pmcg, center=[700, 0, 0], dimensions=[80, 1e8, 1e8], eps=1) + # grid.visualize_isosurface(pmcg) + + +# ss = (1, slice(None), J.shape[2]//2+6, slice(None)) +# pcolor(J3[ss].T.imag) +# pcolor((numpy.abs(J3).sum(axis=(0, 2)) > 0).astype(float).T) +# pyplot.show(block=True) + + E_fdfd = fdfd_solve( + omega = omega, + dxes = dxes, + epsilon = epsilon, + J = J, + pec = pecg, + pmc = pmcg, + ) + + + # + # Plot results + # + center = grid.pos2ind([0, 0, 0], None).astype(int) + fig, axes = pyplot.subplots(2, 2) + pcolor(numpy.real(E[1][center[0], :, :]).T, fig=fig, ax=axes[0, 0]) + axes[0, 1].plot(numpy.log10(numpy.abs(E[1][:, center[1], center[2]]) + 1e-10)) + axes[0, 1].grid(alpha=0.6) + axes[0, 1].set_ylabel('log10 of field') + pcolor(numpy.real(E[1][:, :, center[2]]).T, fig=fig, ax=axes[1, 0]) + + def poyntings(E): + H = functional.e2h(omega, dxes)(E) + poynting = fdtd.poynting(e=E, h=H.conj(), dxes=dxes) + cross1 = operators.poynting_e_cross(vec(E), dxes) @ vec(H).conj() + cross2 = operators.poynting_h_cross(vec(H), dxes) @ vec(E).conj() * -1 + s1 = 0.5 * unvec(numpy.real(cross1), grid.shape) + s2 = 0.5 * unvec(numpy.real(cross2), grid.shape) + s0 = 0.5 * poynting.real +# s2 = poynting.imag + return s0, s1, s2 + + s0x, s1x, s2x = poyntings(E) + axes[1, 1].plot(s0x[0].sum(axis=2).sum(axis=1), label='s0', marker='.') + axes[1, 1].plot(s1x[0].sum(axis=2).sum(axis=1), label='s1', marker='.') + axes[1, 1].plot(s2x[0].sum(axis=2).sum(axis=1), label='s2', marker='.') + axes[1, 1].plot(E[1][:, center[1], center[2]].real.T, label='Ey', marker='x') + axes[1, 1].grid(alpha=0.6) + axes[1, 1].legend() + + q = [] + for i in range(-5, 30): + e_ovl_rolled = numpy.roll(e_overlap, i, axis=1) + q += [numpy.abs(vec(E) @ vec(e_ovl_rolled).conj())] + fig, ax = pyplot.subplots() + ax.plot(q, marker='.') + ax.grid(alpha=0.6) + ax.set_title('Overlap with mode') + + logger.info('Average overlap with mode:', sum(q[8:32]) / len(q[8:32])) + + pyplot.show(block=True) + + +def fdfd_solve( + *, + omega: float, + dxes = dx_lists_t, + epsilon: fdfield_t, + J: cfdfield_t, + pec: fdfield_t, + pmc: fdfield_t, + ) -> cfdfield_t: + """ Construct and run the solve """ + sim_args = dict( + omega = omega, + dxes = dxes, + epsilon = vec(epsilon), + pec = vec(pecg), + pmc = vec(pmcg), + ) + + x = solver(J=vec(J), **sim_args) + + b = -1j * omega * vec(J) + A = operators.e_full(**sim_args).tocsr() + logger.info('Norm of the residual is ', norm(A @ x - b) / norm(b)) + + E = unvec(x, epsilon.shape[1:]) + return E + + +def main2(): + dtype = numpy.float32 + max_t = 3600 # number of timesteps + + dx = 40 # discretization (nm/cell) + pml_thickness = 8 # (number of cells) + + wl = 1550 # Excitation wavelength and fwhm + dwl = 100 + + # Device design parameters + xy_size = numpy.array([10, 10]) + a = 430 + r = 0.285 + th = 170 + + # refractive indices + n_slab = 3.408 # InGaAsP(80, 50) @ 1550nm + n_cladding = 1.0 # air + + # Half-dimensions of the simulation grid + xy_max = (xy_size + 1) * a * [1, numpy.sqrt(3)/2] + z_max = 1.6 * a + xyz_max = numpy.hstack((xy_max, z_max)) + pml_thickness * dx + + # Coordinates of the edges of the cells. The fdtd package can only do square grids at the moment. + half_edge_coords = [numpy.arange(dx/2, m + dx, step=dx) for m in xyz_max] + edge_coords = [numpy.hstack((-h[::-1], h)) for h in half_edge_coords] + + # #### Create the grid, mask, and draw the device #### + grid = gridlock.Grid(edge_coords) + epsilon = grid.allocate(n_cladding ** 2, dtype=dtype) + grid.draw_slab( + epsilon, + slab = dict(axis='z', center=0, span=th), + foreground = n_slab ** 2, + ) + + + print(f'{grid.shape=}') + + dt = dx * 0.99 / numpy.sqrt(3) + ee = numpy.zeros_like(epsilon, dtype=complex) + hh = numpy.zeros_like(epsilon, dtype=complex) + + dxes = [grid.dxyz, grid.autoshifted_dxyz()] + + # PMLs in every direction + pml_params = [ + [cpml_params(axis=dd, polarity=pp, dt=dt, thickness=pml_thickness, epsilon_eff=n_cladding ** 2) + for pp in (-1, +1)] + for dd in range(3)] + update_E, update_H = updates_with_cpml(cpml_params=pml_params, dt=dt, dxes=dxes, epsilon=epsilon, dtype=complex) + + # sample_interval = numpy.floor(1 / (2 * 1 / wl * dt)).astype(int) + # print(f'Save time interval would be {sample_interval} * dt = {sample_interval * dt:3g}') + + + # Sample the pulse at the current half-steps and normalize that scalar + # waveform so the extracted temporal phasor is exactly 1 at omega. + source_phasor, _delay = gaussian_packet(wl=wl, dwl=100, dt=dt, turn_on=1e-5) + aa, cc, ss = source_phasor(numpy.arange(max_t) + 0.5) + source_waveform = aa * (cc + 1j * ss) + omega = 2 * numpy.pi / wl + pulse_scale = fdtd.temporal_phasor_scale(source_waveform, omega, dt, offset_steps=0.5)[0] + + j_source = numpy.zeros_like(epsilon, dtype=complex) + j_source[1, *(grid.shape // 2)] = epsilon[1, *(grid.shape // 2)] + jph = numpy.zeros((1, *epsilon.shape), dtype=complex) + eph = numpy.zeros((1, *epsilon.shape), dtype=complex) + hph = numpy.zeros((1, *epsilon.shape), dtype=complex) + + # #### Run a bunch of iterations #### + output_file = h5py.File('simulation_output.h5', 'w') + start = time.perf_counter() + for tt in range(max_t): + update_E(ee, hh, epsilon) + + # Electric-current injection uses E -= dt * J / epsilon, which is the + # sign convention matched by the FDFD source term -1j * omega * J. + j_step = pulse_scale * source_waveform[tt] * j_source + ee -= dt * j_step / epsilon + update_H(ee, hh) + + avg_rate = (tt + 1) / (time.perf_counter() - start) + + if tt % 200 == 0: + print(f'iteration {tt}: average {avg_rate} iterations per sec') + E_energy_sum = (ee.conj() * ee * epsilon).sum().real + print(f'{E_energy_sum=}') + + # Save field slices + if (tt % 20 == 0 and (max_t - tt <= 1000 or tt <= 2000)) or tt == max_t - 1: + print(f'saving E-field at iteration {tt}') + output_file[f'/E_t{tt}'] = ee[:, :, :, ee.shape[3] // 2] + + fdtd.accumulate_phasor_j(jph, omega, dt, j_step, tt) + fdtd.accumulate_phasor_e(eph, omega, dt, ee, tt + 1) + fdtd.accumulate_phasor_h(hph, omega, dt, hh, tt + 1) + + Eph = eph[0] + Jph = jph[0] + b = -1j * omega * Jph + dxes_fdfd = copy.deepcopy(dxes) + for pp in (-1, +1): + for dd in range(3): + stretch_with_scpml(dxes_fdfd, axis=dd, polarity=pp, omega=omega, epsilon_effective=n_cladding ** 2, thickness=pml_thickness) + # Residuals must be checked on the stretched FDFD grid, because the FDTD run + # already includes those same absorbing layers through CPML. + A = e_full(omega=omega, dxes=dxes_fdfd, epsilon=epsilon) + residual = norm(A @ vec(Eph) - vec(b)) / norm(vec(b)) + print(f'FDFD residual is {residual}') + + +if __name__ == '__main__': + main() diff --git a/examples/waveguide_real.py b/examples/waveguide_real.py new file mode 100644 index 0000000..03a20ac --- /dev/null +++ b/examples/waveguide_real.py @@ -0,0 +1,219 @@ +""" +Real-valued straight-waveguide FDTD/FDFD comparison. + +This example shows the user-facing "compare real FDTD against reconstructed real +FDFD" workflow: + +1. build a straight waveguide on a uniform Yee grid, +2. drive it with a real-valued continuous-wave mode source, +3. solve the matching FDFD problem from the analytic source phasor, and +4. compare late real monitor slices against `fdtd.reconstruct_real_e/h(...)`. + +Unlike the phasor-based examples, this script does not use extracted phasors as +the main output. It is a stricter diagnostic: the comparison target is the raw +real field itself, with full-plane, mode-weighted, guided-mode, and orthogonal- +residual errors reported. Strong phasor agreement can coexist with visibly +larger raw-snapshot error because the latter includes weak nonguided tails on +the monitor plane. +""" + +import numpy + +from meanas import fdfd, fdtd +from meanas.fdfd import functional, scpml, waveguide_3d +from meanas.fdmath import vec, unvec + + +DT = 0.25 +PERIOD_STEPS = 64 +OMEGA = 2 * numpy.pi / (PERIOD_STEPS * DT) +CPML_THICKNESS = 3 +SHAPE = (3, 37, 13, 13) +SOURCE_SLICES = (slice(5, 6), slice(None), slice(None)) +MONITOR_SLICES = (slice(30, 31), slice(None), slice(None)) +WARMUP_PERIODS = 16 +SOURCE_PHASE = 0.4 +CORE_SLICES = (slice(None), slice(None), slice(4, 9), slice(4, 9)) + + +def build_uniform_dxes(shape: tuple[int, int, int, int]) -> list[list[numpy.ndarray]]: + return [[numpy.ones(shape[axis + 1]) for axis in range(3)] for _ in range(2)] + + +def build_epsilon(shape: tuple[int, int, int, int]) -> numpy.ndarray: + epsilon = numpy.ones(shape, dtype=float) + y0 = (shape[2] - 3) // 2 + z0 = (shape[3] - 3) // 2 + epsilon[:, :, y0:y0 + 3, z0:z0 + 3] = 12.0 + return epsilon + + +def build_stretched_dxes(base_dxes: list[list[numpy.ndarray]]) -> list[list[numpy.ndarray]]: + stretched_dxes = [[dx.copy() for dx in group] for group in base_dxes] + for axis in (0, 1, 2): + for polarity in (-1, 1): + stretched_dxes = scpml.stretch_with_scpml( + stretched_dxes, + axis=axis, + polarity=polarity, + omega=OMEGA, + epsilon_effective=1.0, + thickness=CPML_THICKNESS, + ) + return stretched_dxes + + +def build_cpml_params() -> list[list[dict[str, numpy.ndarray | float]]]: + return [ + [fdtd.cpml_params(axis=axis, polarity=polarity, dt=DT, thickness=CPML_THICKNESS, epsilon_eff=1.0) + for polarity in (-1, 1)] + for axis in range(3) + ] + + +def weighted_rel_err(observed: numpy.ndarray, reference: numpy.ndarray, weight: numpy.ndarray) -> float: + return numpy.linalg.norm((observed - reference) * weight) / numpy.linalg.norm(reference * weight) + + +def project_onto_mode(observed: numpy.ndarray, mode: numpy.ndarray) -> tuple[complex, numpy.ndarray, numpy.ndarray]: + coefficient = numpy.vdot(mode, observed) / numpy.vdot(mode, mode) + guided = coefficient * mode + residual = observed - guided + return coefficient, guided, residual + + +def main() -> None: + epsilon = build_epsilon(SHAPE) + base_dxes = build_uniform_dxes(SHAPE) + stretched_dxes = build_stretched_dxes(base_dxes) + + source_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SOURCE_SLICES, + epsilon=epsilon, + ) + j_mode = waveguide_3d.compute_source( + E=source_mode['E'], + wavenumber=source_mode['wavenumber'], + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SOURCE_SLICES, + epsilon=epsilon, + ) + # A small global phase aligns the real-valued source with the late-cycle + # raw-snapshot diagnostic. The underlying phasor problem is unchanged. + j_mode *= numpy.exp(1j * SOURCE_PHASE) + monitor_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=MONITOR_SLICES, + epsilon=epsilon, + ) + e_weight = numpy.abs(monitor_mode['E'][:, MONITOR_SLICES[0], :, :]) + h_weight = numpy.abs(monitor_mode['H'][:, MONITOR_SLICES[0], :, :]) + e_mode = monitor_mode['E'][:, MONITOR_SLICES[0], :, :] + h_mode = monitor_mode['H'][:, MONITOR_SLICES[0], :, :] + + e_fdfd = unvec( + fdfd.solvers.generic( + J=vec(j_mode), + omega=OMEGA, + dxes=stretched_dxes, + epsilon=vec(epsilon), + matrix_solver_opts={'atol': 1e-10, 'rtol': 1e-7}, + ), + SHAPE[1:], + ) + h_fdfd = functional.e2h(OMEGA, stretched_dxes)(e_fdfd) + + update_e, update_h = fdtd.updates_with_cpml( + cpml_params=build_cpml_params(), + dt=DT, + dxes=base_dxes, + epsilon=epsilon, + ) + + e_field = numpy.zeros_like(epsilon) + h_field = numpy.zeros_like(epsilon) + total_steps = (WARMUP_PERIODS + 1) * PERIOD_STEPS + e_errors: list[float] = [] + h_errors: list[float] = [] + e_core_errors: list[float] = [] + h_core_errors: list[float] = [] + e_weighted_errors: list[float] = [] + h_weighted_errors: list[float] = [] + e_guided_errors: list[float] = [] + h_guided_errors: list[float] = [] + e_residual_errors: list[float] = [] + h_residual_errors: list[float] = [] + + for step in range(total_steps): + update_e(e_field, h_field, epsilon) + + # Real-valued FDTD uses the real part of the analytic mode source. + t_half = (step + 0.5) * DT + j_real = (j_mode.real * numpy.cos(OMEGA * t_half) - j_mode.imag * numpy.sin(OMEGA * t_half)).real + e_field -= DT * j_real / epsilon + + update_h(e_field, h_field) + + if step >= total_steps - PERIOD_STEPS // 4: + reconstructed_e = fdtd.reconstruct_real_e( + e_fdfd[:, MONITOR_SLICES[0], :, :], + OMEGA, + DT, + step + 1, + ) + reconstructed_h = fdtd.reconstruct_real_h( + h_fdfd[:, MONITOR_SLICES[0], :, :], + OMEGA, + DT, + step + 1, + ) + + e_monitor = e_field[:, MONITOR_SLICES[0], :, :] + h_monitor = h_field[:, MONITOR_SLICES[0], :, :] + e_errors.append(numpy.linalg.norm(e_monitor - reconstructed_e) / numpy.linalg.norm(reconstructed_e)) + h_errors.append(numpy.linalg.norm(h_monitor - reconstructed_h) / numpy.linalg.norm(reconstructed_h)) + e_core_errors.append( + numpy.linalg.norm(e_monitor[CORE_SLICES] - reconstructed_e[CORE_SLICES]) + / numpy.linalg.norm(reconstructed_e[CORE_SLICES]), + ) + h_core_errors.append( + numpy.linalg.norm(h_monitor[CORE_SLICES] - reconstructed_h[CORE_SLICES]) + / numpy.linalg.norm(reconstructed_h[CORE_SLICES]), + ) + e_weighted_errors.append(weighted_rel_err(e_monitor, reconstructed_e, e_weight)) + h_weighted_errors.append(weighted_rel_err(h_monitor, reconstructed_h, h_weight)) + e_guided_coeff, _, e_residual = project_onto_mode(e_monitor, e_mode) + e_guided_coeff_ref, _, e_residual_ref = project_onto_mode(reconstructed_e, e_mode) + h_guided_coeff, _, h_residual = project_onto_mode(h_monitor, h_mode) + h_guided_coeff_ref, _, h_residual_ref = project_onto_mode(reconstructed_h, h_mode) + e_guided_errors.append(abs(e_guided_coeff - e_guided_coeff_ref) / abs(e_guided_coeff_ref)) + h_guided_errors.append(abs(h_guided_coeff - h_guided_coeff_ref) / abs(h_guided_coeff_ref)) + e_residual_errors.append(numpy.linalg.norm(e_residual - e_residual_ref) / numpy.linalg.norm(e_residual_ref)) + h_residual_errors.append(numpy.linalg.norm(h_residual - h_residual_ref) / numpy.linalg.norm(h_residual_ref)) + + print(f'late-cycle monitor E errors: min={min(e_errors):.4f} max={max(e_errors):.4f}') + print(f'late-cycle monitor H errors: min={min(h_errors):.4f} max={max(h_errors):.4f}') + print(f'late-cycle core-window E errors: min={min(e_core_errors):.4f} max={max(e_core_errors):.4f}') + print(f'late-cycle core-window H errors: min={min(h_core_errors):.4f} max={max(h_core_errors):.4f}') + print(f'late-cycle mode-weighted E errors: min={min(e_weighted_errors):.4f} max={max(e_weighted_errors):.4f}') + print(f'late-cycle mode-weighted H errors: min={min(h_weighted_errors):.4f} max={max(h_weighted_errors):.4f}') + print(f'late-cycle guided-mode E coefficient errors: min={min(e_guided_errors):.4f} max={max(e_guided_errors):.4f}') + print(f'late-cycle guided-mode H coefficient errors: min={min(h_guided_errors):.4f} max={max(h_guided_errors):.4f}') + print(f'late-cycle orthogonal-residual E errors: min={min(e_residual_errors):.4f} max={max(e_residual_errors):.4f}') + print(f'late-cycle orthogonal-residual H errors: min={min(h_residual_errors):.4f} max={max(h_residual_errors):.4f}') + + +if __name__ == '__main__': + main() diff --git a/make_docs.sh b/make_docs.sh index 6d99b5f..6bda9d9 100755 --- a/make_docs.sh +++ b/make_docs.sh @@ -2,18 +2,20 @@ set -Eeuo pipefail -cd ~/projects/meanas +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$ROOT" -# Approach 1: pdf to html? -#pdoc3 --pdf --force --template-dir pdoc_templates -o doc . | \ -# pandoc --metadata=title:"meanas" --toc --toc-depth=4 --from=markdown+abbreviations --to=html --output=doc.html --gladtex -s - +DOCS_TMP="$(mktemp -d)" +cleanup() { + rm -rf "$DOCS_TMP" +} +trap cleanup EXIT -# Approach 2: pdf to html with gladtex -rm -rf _doc_mathimg -pdoc --pdf --force --template-dir pdoc_templates -o doc . > doc.md -pandoc --metadata=title:"meanas" --from=markdown+abbreviations --to=html --output=doc.htex --gladtex -s --css pdoc_templates/pdoc.css doc.md -gladtex -a -n -d _doc_mathimg -c white -b black doc.htex +python3 "$ROOT/scripts/prepare_docs_sources.py" "$ROOT/meanas" "$DOCS_TMP" -# Approach 3: html with gladtex -#pdoc3 --html --force --template-dir pdoc_templates -o doc . -#find doc -iname '*.html' -exec gladtex -a -n -d _mathimg -c white {} \; +MKDOCSTRINGS_PYTHON_PATH="$DOCS_TMP" mkdocs build --clean + +PRINT_PAGE='site/print_page/index.html' +if [[ -f "$PRINT_PAGE" ]] && command -v htmlark >/dev/null 2>&1; then + htmlark "$PRINT_PAGE" -o site/standalone.html +fi diff --git a/meanas/__init__.py b/meanas/__init__.py index 354adc9..9d1b401 100644 --- a/meanas/__init__.py +++ b/meanas/__init__.py @@ -1,18 +1,19 @@ """ Electromagnetic simulation tools -See the readme or `import meanas; help(meanas)` for more info. +See the tracked examples for end-to-end workflows, and `help(meanas)` for the +toolbox overview and API derivations. """ import pathlib -__version__ = '0.9' +__version__ = '0.12' __author__ = 'Jan Petykiewicz' try: - with open(pathlib.Path(__file__).parent / 'README.md', 'r') as f: + readme_path = pathlib.Path(__file__).parent / 'README.md' + with readme_path.open('r') as f: __doc__ = f.read() except Exception: pass - diff --git a/meanas/eigensolvers.py b/meanas/eigensolvers.py index ac64f5c..98e7a15 100644 --- a/meanas/eigensolvers.py +++ b/meanas/eigensolvers.py @@ -1,12 +1,12 @@ """ Solvers for eigenvalue / eigenvector problems """ -from typing import Callable +from collections.abc import Callable import numpy from numpy.typing import NDArray, ArrayLike from numpy.linalg import norm -from scipy import sparse # type: ignore -import scipy.sparse.linalg as spalg # type: ignore +from scipy import sparse +import scipy.sparse.linalg as spalg def power_iteration( @@ -25,8 +25,9 @@ def power_iteration( Returns: (Largest-magnitude eigenvalue, Corresponding eigenvector estimate) """ + rng = numpy.random.default_rng() if guess_vector is None: - v = numpy.random.rand(operator.shape[0]) + 1j * numpy.random.rand(operator.shape[0]) + v = rng.random(operator.shape[0]) + 1j * rng.random(operator.shape[0]) else: v = guess_vector @@ -63,10 +64,10 @@ def rayleigh_quotient_iteration( (eigenvalues, eigenvectors) """ try: - (operator - sparse.eye(operator.shape[0])) + (operator - sparse.eye_array(operator.shape[0])) - def shift(eigval: float) -> sparse: - return eigval * sparse.eye(operator.shape[0]) + def shift(eigval: float) -> sparse.sparray: + return eigval * sparse.eye_array(operator.shape[0]) if solver is None: solver = spalg.spsolve @@ -129,12 +130,12 @@ def signed_eigensolve( # Try to combine, use general LinearOperator if we fail try: - shifted_operator = operator + shift * sparse.eye(operator.shape[0]) + shifted_operator = operator + shift * sparse.eye_array(operator.shape[0]) except TypeError: shifted_operator = operator + spalg.LinearOperator(shape=operator.shape, matvec=lambda v: shift * v) - shifted_eigenvalues, eigenvectors = spalg.eigs(shifted_operator, which='LM', k=how_many, ncv=50) + shifted_eigenvalues, eigenvectors = spalg.eigs(shifted_operator, which='LM', k=how_many, ncv=2 * how_many + 50) eigenvalues = shifted_eigenvalues - shift k = eigenvalues.argsort() diff --git a/meanas/fdfd/__init__.py b/meanas/fdfd/__init__.py index 1829cf9..e94adc3 100644 --- a/meanas/fdfd/__init__.py +++ b/meanas/fdfd/__init__.py @@ -9,9 +9,12 @@ Submodules: - `operators`, `functional`: General FDFD problem setup. - `solvers`: Solver interface and reference implementation. -- `scpml`: Stretched-coordinate perfectly matched layer (scpml) boundary conditions +- `scpml`: Stretched-coordinate perfectly matched layer (SCPML) boundary conditions. - `waveguide_2d`: Operators and mode-solver for waveguides with constant cross-section. -- `waveguide_3d`: Functions for transforming `waveguide_2d` results into 3D. +- `waveguide_3d`: Functions for transforming `waveguide_2d` results into 3D, + including mode-source and overlap-window construction. +- `farfield`, `bloch`, `eme`: specialized helper modules for near/far transforms, + Bloch-periodic problems, and eigenmode expansion. ================================================================ @@ -86,10 +89,13 @@ $$ -\omega^2 \epsilon_{\vec{r}} \cdot \tilde{E}_{\vec{r}} = -\imath \omega \tilde{J}_{\vec{r}} \\ $$ -# TODO FDFD? -# TODO PML - - """ -from . import solvers, operators, functional, scpml, waveguide_2d, waveguide_3d +from . import ( + solvers as solvers, + operators as operators, + functional as functional, + scpml as scpml, + waveguide_2d as waveguide_2d, + waveguide_3d as waveguide_3d, + ) # from . import farfield, bloch TODO diff --git a/meanas/fdfd/bloch.py b/meanas/fdfd/bloch.py index 0d0ac1a..1e15c3a 100644 --- a/meanas/fdfd/bloch.py +++ b/meanas/fdfd/bloch.py @@ -94,18 +94,19 @@ This module contains functions for generating and solving the """ -from typing import Callable, Any, cast, Sequence +from typing import Any, cast +from collections.abc import Callable, Sequence import logging import numpy from numpy import pi, real, trace from numpy.fft import fftfreq from numpy.typing import NDArray, ArrayLike -import scipy # type: ignore -import scipy.optimize # type: ignore -from scipy.linalg import norm # type: ignore -import scipy.sparse.linalg as spalg # type: ignore +import scipy +import scipy.optimize +from scipy.linalg import norm +import scipy.sparse.linalg as spalg -from ..fdmath import fdfield_t, cfdfield_t +from ..fdmath import fdfield, cfdfield, cfdfield_t logger = logging.getLogger(__name__) @@ -114,7 +115,6 @@ logger = logging.getLogger(__name__) try: import pyfftw.interfaces.numpy_fft # type: ignore import pyfftw.interfaces # type: ignore - import multiprocessing logger.info('Using pyfftw') pyfftw.interfaces.cache.enable() @@ -136,6 +136,14 @@ except ImportError: logger.info('Using numpy fft') +def _assemble_hmn_vector( + h_m: NDArray[numpy.complex128], + h_n: NDArray[numpy.complex128], + ) -> NDArray[numpy.complex128]: + stacked = numpy.concatenate((numpy.ravel(h_m), numpy.ravel(h_n))) + return stacked[:, None] + + def generate_kmn( k0: ArrayLike, G_matrix: ArrayLike, @@ -155,7 +163,7 @@ def generate_kmn( All are given in the xyz basis (e.g. `|k|[0,0,0] = norm(G_matrix @ k0)`). """ k0 = numpy.array(k0) - G_matrix = numpy.array(G_matrix, copy=False) + G_matrix = numpy.asarray(G_matrix) Gi_grids = numpy.array(numpy.meshgrid(*(fftfreq(n, 1 / n) for n in shape[:3]), indexing='ij')) Gi = numpy.moveaxis(Gi_grids, 0, -1) @@ -183,8 +191,8 @@ def generate_kmn( def maxwell_operator( k0: ArrayLike, G_matrix: ArrayLike, - epsilon: fdfield_t, - mu: fdfield_t | None = None + epsilon: fdfield, + mu: fdfield | None = None ) -> Callable[[NDArray[numpy.complex128]], NDArray[numpy.complex128]]: """ Generate the Maxwell operator @@ -232,13 +240,13 @@ def maxwell_operator( Raveled conv(1/mu_k, ik x conv(1/eps_k, ik x h_mn)), returned and overwritten in-place of `h`. """ - hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)] + hin_m, hin_n = (hi.reshape(shape) for hi in numpy.split(h, 2)) #{d,e,h}_xyz fields are complex 3-fields in (1/x, 1/y, 1/z) basis # cross product and transform into xyz basis d_xyz = (n * hin_m - - m * hin_n) * k_mag # noqa: E128 + - m * hin_n) * k_mag # divide by epsilon temp = ifftn(d_xyz, axes=range(3)) # reuses d_xyz if using pyfftw @@ -253,8 +261,8 @@ def maxwell_operator( h_m, h_n = b_m, b_n else: # transform from mn to xyz - b_xyz = (m * b_m[:, :, :, None] - + n * b_n[:, :, :, None]) # noqa: E128 + b_xyz = (m * b_m + + n * b_n) # noqa # divide by mu temp = ifftn(b_xyz, axes=range(3)) @@ -265,10 +273,7 @@ def maxwell_operator( h_m = numpy.sum(h_xyz * m, axis=3) h_n = numpy.sum(h_xyz * n, axis=3) - h.shape = (h.size,) - h = numpy.concatenate((h_m.ravel(), h_n.ravel()), axis=None, out=h) # ravel and merge - h.shape = (h.size, 1) - return h + return _assemble_hmn_vector(h_m, h_n) return operator @@ -276,7 +281,7 @@ def maxwell_operator( def hmn_2_exyz( k0: ArrayLike, G_matrix: ArrayLike, - epsilon: fdfield_t, + epsilon: fdfield, ) -> Callable[[NDArray[numpy.complex128]], cfdfield_t]: """ Generate an operator which converts a vectorized spatial-frequency-space @@ -303,12 +308,13 @@ def hmn_2_exyz( k_mag, m, n = generate_kmn(k0, G_matrix, shape) def operator(h: NDArray[numpy.complex128]) -> cfdfield_t: - hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)] + hin_m, hin_n = (hi.reshape(shape) for hi in numpy.split(h, 2)) d_xyz = (n * hin_m - - m * hin_n) * k_mag # noqa: E128 + - m * hin_n) * k_mag # divide by epsilon - return numpy.array([ei for ei in numpy.moveaxis(ifftn(d_xyz, axes=range(3)) / epsilon, 3, 0)]) # TODO avoid copy + exyz = numpy.moveaxis(ifftn(d_xyz, axes=range(3)) / epsilon, 3, 0) + return cfdfield_t(exyz) return operator @@ -316,7 +322,7 @@ def hmn_2_exyz( def hmn_2_hxyz( k0: ArrayLike, G_matrix: ArrayLike, - epsilon: fdfield_t + epsilon: fdfield, ) -> Callable[[NDArray[numpy.complex128]], cfdfield_t]: """ Generate an operator which converts a vectorized spatial-frequency-space @@ -341,10 +347,10 @@ def hmn_2_hxyz( _k_mag, m, n = generate_kmn(k0, G_matrix, shape) def operator(h: NDArray[numpy.complex128]) -> cfdfield_t: - hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)] + hin_m, hin_n = (hi.reshape(shape) for hi in numpy.split(h, 2)) h_xyz = (m * hin_m - + n * hin_n) # noqa: E128 - return numpy.array([ifftn(hi) for hi in numpy.moveaxis(h_xyz, 3, 0)]) + + n * hin_n) + return cfdfield_t(numpy.array([ifftn(hi) for hi in numpy.moveaxis(h_xyz, 3, 0)])) return operator @@ -352,8 +358,8 @@ def hmn_2_hxyz( def inverse_maxwell_operator_approx( k0: ArrayLike, G_matrix: ArrayLike, - epsilon: fdfield_t, - mu: fdfield_t | None = None, + epsilon: fdfield, + mu: fdfield | None = None, ) -> Callable[[NDArray[numpy.complex128]], NDArray[numpy.complex128]]: """ Generate an approximate inverse of the Maxwell operator, @@ -394,7 +400,7 @@ def inverse_maxwell_operator_approx( Returns: Raveled ik x conv(eps_k, ik x conv(mu_k, h_mn)) """ - hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)] + hin_m, hin_n = (hi.reshape(shape) for hi in numpy.split(h, 2)) #{d,e,h}_xyz fields are complex 3-fields in (1/x, 1/y, 1/z) basis @@ -402,8 +408,8 @@ def inverse_maxwell_operator_approx( b_m, b_n = hin_m, hin_n else: # transform from mn to xyz - h_xyz = (m * hin_m[:, :, :, None] - + n * hin_n[:, :, :, None]) # noqa: E128 + h_xyz = (m * hin_m + + n * hin_n) # noqa # multiply by mu temp = ifftn(h_xyz, axes=range(3)) @@ -411,12 +417,12 @@ def inverse_maxwell_operator_approx( b_xyz = fftn(temp, axes=range(3)) # transform back to mn - b_m = numpy.sum(b_xyz * m, axis=3) - b_n = numpy.sum(b_xyz * n, axis=3) + b_m = numpy.sum(b_xyz * m, axis=3, keepdims=True) + b_n = numpy.sum(b_xyz * n, axis=3, keepdims=True) # cross product and transform into xyz basis e_xyz = (n * b_m - - m * b_n) / k_mag # noqa: E128 + - m * b_n) / k_mag # multiply by epsilon temp = ifftn(e_xyz, axes=range(3)) @@ -427,10 +433,7 @@ def inverse_maxwell_operator_approx( h_m = numpy.sum(d_xyz * n, axis=3, keepdims=True) / +k_mag h_n = numpy.sum(d_xyz * m, axis=3, keepdims=True) / -k_mag - h.shape = (h.size,) - h = numpy.concatenate((h_m, h_n), axis=None, out=h) - h.shape = (h.size, 1) - return h + return _assemble_hmn_vector(h_m, h_n) return operator @@ -440,15 +443,15 @@ def find_k( tolerance: float, direction: ArrayLike, G_matrix: ArrayLike, - epsilon: fdfield_t, - mu: fdfield_t | None = None, + epsilon: fdfield, + mu: fdfield | None = None, band: int = 0, k_bounds: tuple[float, float] = (0, 0.5), k_guess: float | None = None, solve_callback: Callable[..., None] | None = None, iter_callback: Callable[..., None] | None = None, v0: NDArray[numpy.complex128] | None = None, - ) -> tuple[float, float, NDArray[numpy.complex128], NDArray[numpy.complex128]]: + ) -> tuple[NDArray[numpy.float64], float, NDArray[numpy.complex128], NDArray[numpy.complex128]]: """ Search for a bloch vector that has a given frequency. @@ -471,7 +474,7 @@ def find_k( `(k, actual_frequency, eigenvalues, eigenvectors)` The found k-vector and its frequency, along with all eigenvalues and eigenvectors. """ - direction = numpy.array(direction) / norm(direction) + direction = numpy.array(direction) / norm(direction) # type: ignore[operator] k_bounds = tuple(sorted(k_bounds)) # type: ignore # we know the length already... assert len(k_bounds) == 2 @@ -493,23 +496,23 @@ def find_k( res = scipy.optimize.minimize_scalar( lambda x: abs(get_f(x, band) - frequency), - k_guess, - method='Bounded', + method='bounded', bounds=k_bounds, options={'xatol': abs(tolerance)}, ) assert n is not None assert v is not None - return float(res.x * direction), float(res.fun + frequency), n, v + actual_frequency = get_f(float(res.x), band) + return direction * float(res.x), float(actual_frequency), n, v # type: ignore[operator,return-value] def eigsolve( num_modes: int, k0: ArrayLike, G_matrix: ArrayLike, - epsilon: fdfield_t, - mu: fdfield_t | None = None, + epsilon: fdfield, + mu: fdfield | None = None, tolerance: float = 1e-7, max_iters: int = 10000, reset_iters: int = 100, @@ -538,7 +541,7 @@ def eigsolve( `(eigenvalues, eigenvectors)` where `eigenvalues[i]` corresponds to the vector `eigenvectors[i, :]` """ - k0 = numpy.array(k0, copy=False) + k0 = numpy.asarray(k0) h_size = 2 * epsilon[0].size @@ -561,11 +564,12 @@ def eigsolve( prev_theta = 0.5 D = numpy.zeros(shape=y_shape, dtype=complex) + rng = numpy.random.default_rng() Z: NDArray[numpy.complex128] if y0 is None: - Z = numpy.random.rand(*y_shape) + 1j * numpy.random.rand(*y_shape) + Z = rng.random(y_shape) + 1j * rng.random(y_shape) else: - Z = numpy.array(y0, copy=False).T + Z = numpy.asarray(y0).T while True: Z *= num_modes / norm(Z) @@ -573,7 +577,7 @@ def eigsolve( try: U = numpy.linalg.inv(ZtZ) except numpy.linalg.LinAlgError: - Z = numpy.random.rand(*y_shape) + 1j * numpy.random.rand(*y_shape) + Z = rng.random(y_shape) + 1j * rng.random(y_shape) continue trace_U = real(trace(U)) @@ -646,17 +650,16 @@ def eigsolve( Qi_memo: list[float | None] = [None, None] - def Qi_func(theta: float) -> float: - nonlocal Qi_memo + def Qi_func(theta: float, Qi_memo=Qi_memo, ZtZ=ZtZ, DtD=DtD, symZtD=symZtD) -> float: # noqa: ANN001 if Qi_memo[0] == theta: - return cast(float, Qi_memo[1]) + return cast('float', Qi_memo[1]) c = numpy.cos(theta) s = numpy.sin(theta) Q = c * c * ZtZ + s * s * DtD + 2 * s * c * symZtD try: Qi = numpy.linalg.inv(Q) - except numpy.linalg.LinAlgError: + except numpy.linalg.LinAlgError as err: logger.info('taylor Qi') # if c or s small, taylor expand if c < 1e-4 * s and c != 0: @@ -666,12 +669,12 @@ def eigsolve( ZtZi = numpy.linalg.inv(ZtZ) Qi = ZtZi / (c * c) - 2 * s / (c * c * c) * (ZtZi @ (ZtZi @ symZtD).conj().T) else: - raise Exception('Inexplicable singularity in trace_func') + raise Exception('Inexplicable singularity in trace_func') from err Qi_memo[0] = theta - Qi_memo[1] = cast(float, Qi) - return cast(float, Qi) + Qi_memo[1] = cast('float', Qi) + return cast('float', Qi) - def trace_func(theta: float) -> float: + def trace_func(theta: float, ZtAZ=ZtAZ, DtAD=DtAD, symZtAD=symZtAD) -> float: # noqa: ANN001 c = numpy.cos(theta) s = numpy.sin(theta) Qi = Qi_func(theta) @@ -680,7 +683,16 @@ def eigsolve( return numpy.abs(trace) if False: - def trace_deriv(theta): + def trace_deriv( + theta: float, + sgn: int = sgn, + ZtAZ=ZtAZ, # noqa: ANN001 + DtAD=DtAD, # noqa: ANN001 + symZtD=symZtD, # noqa: ANN001 + symZtAD=symZtAD, # noqa: ANN001 + ZtZ=ZtZ, # noqa: ANN001 + DtD=DtD, # noqa: ANN001 + ) -> float: Qi = Qi_func(theta) c2 = numpy.cos(2 * theta) s2 = numpy.sin(2 * theta) @@ -722,7 +734,12 @@ def eigsolve( amax=pi, ) - result = scipy.optimize.minimize_scalar(trace_func, bounds=(0, pi), tol=tolerance) + result = scipy.optimize.minimize_scalar( + trace_func, + method='bounded', + bounds=(0, pi), + options={'xatol': tolerance}, + ) new_E = result.fun theta = result.x @@ -751,7 +768,7 @@ def eigsolve( v = eigvecs[:, i] n = eigvals[i] v /= norm(v) - Av = (scipy_op @ v.copy())[:, 0] + Av = numpy.asarray(scipy_op @ v.copy()).reshape(-1) eigness = norm(Av - (v.conj() @ Av) * v) f = numpy.sqrt(-numpy.real(n)) df = numpy.sqrt(-numpy.real(n) + eigness) @@ -799,3 +816,62 @@ def _rtrace_AtB( def _symmetrize(A: NDArray[numpy.complex128]) -> NDArray[numpy.complex128]: return (A + A.conj().T) * 0.5 + + +def inner_product( + eL: cfdfield, + hL: cfdfield, + eR: cfdfield, + hR: cfdfield, + ) -> complex: + # assumes x-axis propagation + + assert numpy.array_equal(eR.shape, hR.shape) + assert numpy.array_equal(eL.shape, hL.shape) + assert numpy.array_equal(eR.shape, eL.shape) + + # Cross product, times 2 since it's

, then divide by 4. # TODO might want to abs() this? + norm2R = (eR[1] * hR[2] - eR[2] * hR[1]).sum() / 2 + norm2L = (eL[1] * hL[2] - eL[2] * hL[1]).sum() / 2 + + # eRxhR_x = numpy.cross(eR.reshape(3, -1), hR.reshape(3, -1), axis=0).reshape(eR.shape)[0] / normR + # logger.info(f'power {eRxhR_x.sum() / 2}) + + eR_norm = eR / numpy.sqrt(abs(norm2R)) + hR_norm = hR / numpy.sqrt(abs(norm2R)) + eL_norm = eL / numpy.sqrt(abs(norm2L)) + hL_norm = hL / numpy.sqrt(abs(norm2L)) + + # (eR x hL)[0] and (eL x hR)[0] + eRxhL_x = eR_norm[1] * hL_norm[2] - eR_norm[2] * hL_norm[1] + eLxhR_x = eL_norm[1] * hR_norm[2] - eL_norm[2] * hR_norm[1] + + #return 1j * (eRxhL_x - eLxhR_x).sum() / numpy.sqrt(norm2R * norm2L) + #return (eRxhL_x.sum() - eLxhR_x.sum()) / numpy.sqrt(norm2R * norm2L) + return eLxhR_x.sum() - eRxhL_x.sum() + + +def trq( + eI: cfdfield, + hI: cfdfield, + eO: cfdfield, + hO: cfdfield, + ) -> tuple[complex, complex]: + pp = inner_product(eO, hO, eI, hI) + pn = inner_product(eO, hO, eI, -hI) + np = inner_product(eO, -hO, eI, hI) + nn = inner_product(eO, -hO, eI, -hI) + + assert numpy.allclose(pp, -nn, atol=1e-12, rtol=1e-12) + assert numpy.allclose(pn, -np, atol=1e-12, rtol=1e-12) + + logger.info(f''' + {pp=:4g} {pn=:4g} + {nn=:4g} {np=:4g} + {nn * pp / pn=:4g} {-np=:4g} + ''') + + r = -pp / pn # -/ = -(-pp) / (-pn) + t = (np - nn * pp / pn) / 4 + + return t, r diff --git a/meanas/fdfd/eme.py b/meanas/fdfd/eme.py new file mode 100644 index 0000000..af745e8 --- /dev/null +++ b/meanas/fdfd/eme.py @@ -0,0 +1,190 @@ +""" +Low-level mode-matching helpers for waveguide / EME workflows. + +These helpers operate on already-solved and already-normalized port fields. +They do not build geometries or solve modes themselves; downstream users are +expected to supply compatible `(E, H)` modal field pairs from +`waveguide_2d`, `waveguide_3d`, or `waveguide_cyl`. + +The returned matrices follow the usual port ordering: + +- `get_tr(...)` returns `(T, R)` for left-incident modes. +- `get_abcd(...)` returns the 2-port block transfer matrix built from the two + directional `T/R` solves. +- `get_s(...)` returns the full block scattering matrix + `[[R12, T12], [T21, R21]]`. + +This module is intentionally a thin library layer rather than an integrated +simulation suite. It provides the overlap algebra that downstream users can +compose into larger workflows. +""" + +from collections.abc import Sequence +import numpy +from numpy.typing import NDArray +from scipy import sparse + +from ..fdmath import dx_lists2_t, vcfdfield2 +from .waveguide_2d import inner_product + +type wavenumber_seq = Sequence[complex] | NDArray[numpy.complexfloating] | NDArray[numpy.floating] + + +def _validate_port_modes( + name: str, + ehs: Sequence[Sequence[vcfdfield2]], + wavenumbers: wavenumber_seq, + ) -> tuple[tuple[int, ...], tuple[int, ...]]: + if len(ehs) != len(wavenumbers): + raise ValueError(f'{name} mode list and wavenumber list must have the same length') + if not ehs: + raise ValueError(f'{name} must contain at least one mode') + + e_shape: tuple[int, ...] | None = None + h_shape: tuple[int, ...] | None = None + for index, mode in enumerate(ehs): + if len(mode) != 2: + raise ValueError(f'{name}[{index}] must be a 2-tuple of (E, H) modal fields') + e_field, h_field = mode + mode_e_shape = numpy.shape(e_field) + mode_h_shape = numpy.shape(h_field) + if mode_e_shape != mode_h_shape: + raise ValueError(f'{name}[{index}] has mismatched E/H field shapes') + if e_shape is None: + e_shape = mode_e_shape + h_shape = mode_h_shape + elif mode_e_shape != e_shape or mode_h_shape != h_shape: + raise ValueError(f'{name} modal fields must all share the same shape') + + assert e_shape is not None + assert h_shape is not None + return e_shape, h_shape + + +def get_tr( + ehLs: Sequence[Sequence[vcfdfield2]], + wavenumbers_L: wavenumber_seq, + ehRs: Sequence[Sequence[vcfdfield2]], + wavenumbers_R: wavenumber_seq, + dxes: dx_lists2_t, + ) -> tuple[NDArray[numpy.complex128], NDArray[numpy.complex128]]: + """ + Compute left-incident transmission and reflection matrices. + + Args: + ehLs: Left-port modes as `(E, H)` field pairs. + wavenumbers_L: Propagation constants for `ehLs`. + ehRs: Right-port modes as `(E, H)` field pairs. + wavenumbers_R: Propagation constants for `ehRs`. + dxes: Two-dimensional Yee-cell edge lengths for the shared port plane. + + Returns: + `(T12, R12)` where columns index left-incident modes and rows index + outgoing right-going / left-going modes respectively. + + Raises: + ValueError: If the port mode lists are empty, malformed, or defined on + incompatible field shapes. + """ + left_e_shape, left_h_shape = _validate_port_modes('ehLs', ehLs, wavenumbers_L) + right_e_shape, right_h_shape = _validate_port_modes('ehRs', ehRs, wavenumbers_R) + if left_e_shape != right_e_shape or left_h_shape != right_h_shape: + raise ValueError('left and right modal fields must share the same E/H shapes') + + nL = len(wavenumbers_L) + nR = len(wavenumbers_R) + A12 = numpy.zeros((nL, nR), dtype=complex) + A21 = numpy.zeros((nL, nR), dtype=complex) + B11 = numpy.zeros((nL,), dtype=complex) + for ll in range(nL): + eL, hL = ehLs[ll] + B11[ll] = inner_product(eL, hL, dxes=dxes, conj_h=False) + for rr in range(nR): + eR, hR = ehRs[rr] + A12[ll, rr] = inner_product(eL, hR, dxes=dxes, conj_h=False) # TODO optimize loop? + A21[ll, rr] = inner_product(eR, hL, dxes=dxes, conj_h=False) + + # tt0 = 2 * numpy.linalg.pinv(A21 + numpy.conj(A12)) + tt0, _resid, _rank, _sing = numpy.linalg.lstsq(A21 + A12, numpy.diag(2 * B11), rcond=None) + + U, st, V = numpy.linalg.svd(tt0) + gain = st > 1 + st[gain] = 1 / st[gain] + tt = U @ numpy.diag(st) @ V + + # rr = 0.5 * (A21 - numpy.conj(A12)) @ tt + rr = numpy.diag(0.5 / B11) @ (A21 - A12) @ tt + + return tt, rr + + +def get_abcd( + ehLs: Sequence[Sequence[vcfdfield2]], + wavenumbers_L: wavenumber_seq, + ehRs: Sequence[Sequence[vcfdfield2]], + wavenumbers_R: wavenumber_seq, + **kwargs, + ) -> sparse.sparray: + """ + Build the 2-port block transfer matrix for an interface. + + The blocks are assembled from the forward and reverse `get_tr(...)` + solutions using the standard + + `[[A, B], [C, D]] = [[T12 - R21 T21^-1 R12, R21 T21^-1], [-T21^-1 R12, T21^-1]]` + + convention. + """ + t12, r12 = get_tr(ehLs, wavenumbers_L, ehRs, wavenumbers_R, **kwargs) + t21, r21 = get_tr(ehRs, wavenumbers_R, ehLs, wavenumbers_L, **kwargs) + t21i = numpy.linalg.pinv(t21) + A = t12 - r21 @ t21i @ r12 + B = r21 @ t21i + C = -t21i @ r12 + D = t21i + return sparse.block_array( + [ + [sparse.csr_array(A), sparse.csr_array(B)], + [sparse.csr_array(C), sparse.csr_array(D)], + ], + format='csr', + ) + + +def get_s( + ehLs: Sequence[Sequence[vcfdfield2]], + wavenumbers_L: wavenumber_seq, + ehRs: Sequence[Sequence[vcfdfield2]], + wavenumbers_R: wavenumber_seq, + force_nogain: bool = False, + force_reciprocal: bool = False, + **kwargs, + ) -> NDArray[numpy.complex128]: + """ + Build the full block scattering matrix for a two-sided interface. + + The returned matrix is ordered as `[[R12, T12], [T21, R21]]`, where the + first block-row/column corresponds to the left port and the second to the + right port. + + Args: + force_nogain: If `True`, clamp singular values of the assembled + scattering matrix to at most one. + force_reciprocal: If `True`, symmetrize the assembled matrix as + `0.5 * (S + S.T)`. + """ + t12, r12 = get_tr(ehLs, wavenumbers_L, ehRs, wavenumbers_R, **kwargs) + t21, r21 = get_tr(ehRs, wavenumbers_R, ehLs, wavenumbers_L, **kwargs) + + ss = numpy.block([[r12, t12], + [t21, r21]]) + + if force_nogain: + # force S @ S.H diagonal + U, sing, Vh = numpy.linalg.svd(ss) + ss = U @ numpy.diag(numpy.minimum(sing, 1.0)) @ Vh + + if force_reciprocal: + ss = 0.5 * (ss + ss.T) + + return ss diff --git a/meanas/fdfd/farfield.py b/meanas/fdfd/farfield.py index 5c1caf0..06f705b 100644 --- a/meanas/fdfd/farfield.py +++ b/meanas/fdfd/farfield.py @@ -1,20 +1,24 @@ """ Functions for performing near-to-farfield transformation (and the reverse). """ -from typing import Any, Sequence, cast +from typing import Any, cast +from collections.abc import Sequence import numpy from numpy.fft import fft2, fftshift, fftfreq, ifft2, ifftshift from numpy import pi +from numpy.typing import NDArray +from numpy import complexfloating -from ..fdmath import cfdfield_t +type farfield_slice = NDArray[complexfloating] +type transverse_slice_pair = Sequence[farfield_slice] def near_to_farfield( - E_near: cfdfield_t, - H_near: cfdfield_t, + E_near: transverse_slice_pair, + H_near: transverse_slice_pair, dx: float, dy: float, - padded_size: list[int] | int | None = None + padded_size: Sequence[int] | int | None = None ) -> dict[str, Any]: """ Compute the farfield, i.e. the distribution of the fields after propagation @@ -55,14 +59,14 @@ def near_to_farfield( raise Exception('H_near must be a length-2 list of ndarrays') s = E_near[0].shape - if not all(s == f.shape for f in E_near + H_near): + if not all(s == f.shape for f in [*E_near, *H_near]): raise Exception('All fields must be the same shape!') if padded_size is None: padded_size = (2**numpy.ceil(numpy.log2(s))).astype(int) if not hasattr(padded_size, '__len__'): padded_size = (padded_size, padded_size) # type: ignore # checked if sequence - padded_shape = cast(Sequence[int], padded_size) + padded_shape = cast('Sequence[int]', padded_size) En_fft = [fftshift(fft2(fftshift(Eni), s=padded_shape)) for Eni in E_near] Hn_fft = [fftshift(fft2(fftshift(Hni), s=padded_shape)) for Hni in H_near] @@ -75,25 +79,22 @@ def near_to_farfield( kx, ky = numpy.meshgrid(kxx, kyy, indexing='ij') kxy2 = kx * kx + ky * ky kxy = numpy.sqrt(kxy2) - kz = numpy.sqrt(k * k - kxy2) + kz = numpy.sqrt(numpy.maximum(0, k * k - kxy2)) - sin_th = ky / kxy - cos_th = kx / kxy + sin_th = numpy.divide(ky, kxy, out=numpy.zeros_like(ky), where=kxy != 0) + cos_th = numpy.divide(kx, kxy, out=numpy.ones_like(kx), where=kxy != 0) cos_phi = kz / k - sin_th[numpy.logical_and(kx == 0, ky == 0)] = 0 - cos_th[numpy.logical_and(kx == 0, ky == 0)] = 1 - # Normalized vector potentials N, L N = [-Hn_fft[1] * cos_phi * cos_th + Hn_fft[0] * cos_phi * sin_th, - Hn_fft[1] * sin_th + Hn_fft[0] * cos_th] # noqa: E127 + Hn_fft[1] * sin_th + Hn_fft[0] * cos_th] # noqa L = [ En_fft[1] * cos_phi * cos_th - En_fft[0] * cos_phi * sin_th, - -En_fft[1] * sin_th - En_fft[0] * cos_th] # noqa: E128 + -En_fft[1] * sin_th - En_fft[0] * cos_th] # noqa E_far = [-L[1] - N[0], - L[0] - N[1]] # noqa: E127 + L[0] - N[1]] # noqa H_far = [-E_far[1], - E_far[0]] # noqa: E127 + E_far[0]] # noqa theta = numpy.arctan2(ky, kx) phi = numpy.arccos(cos_phi) @@ -111,8 +112,8 @@ def near_to_farfield( outputs = { 'E': E_far, 'H': H_far, - 'dkx': kx[1] - kx[0], - 'dky': ky[1] - ky[0], + 'dkx': float(kxx[1] - kxx[0]), + 'dky': float(kyy[1] - kyy[0]), 'kx': kx, 'ky': ky, 'theta': theta, @@ -123,11 +124,11 @@ def near_to_farfield( def far_to_nearfield( - E_far: cfdfield_t, - H_far: cfdfield_t, + E_far: transverse_slice_pair, + H_far: transverse_slice_pair, dkx: float, dky: float, - padded_size: list[int] | int | None = None + padded_size: Sequence[int] | int | None = None ) -> dict[str, Any]: """ Compute the farfield, i.e. the distribution of the fields after propagation @@ -164,32 +165,29 @@ def far_to_nearfield( raise Exception('H_far must be a length-2 list of ndarrays') s = E_far[0].shape - if not all(s == f.shape for f in E_far + H_far): + if not all(s == f.shape for f in [*E_far, *H_far]): raise Exception('All fields must be the same shape!') if padded_size is None: padded_size = (2 ** numpy.ceil(numpy.log2(s))).astype(int) if not hasattr(padded_size, '__len__'): padded_size = (padded_size, padded_size) # type: ignore # checked if sequence - padded_shape = cast(Sequence[int], padded_size) + padded_shape = cast('Sequence[int]', padded_size) k = 2 * pi - kxs = fftshift(fftfreq(s[0], 1 / (s[0] * dkx))) - kys = fftshift(fftfreq(s[0], 1 / (s[1] * dky))) + kxs = dkx * fftshift(fftfreq(s[0], d=1 / s[0])) + kys = dky * fftshift(fftfreq(s[1], d=1 / s[1])) kx, ky = numpy.meshgrid(kxs, kys, indexing='ij') kxy2 = kx * kx + ky * ky kxy = numpy.sqrt(kxy2) - kz = numpy.sqrt(k * k - kxy2) + kz = numpy.sqrt(numpy.maximum(0, k * k - kxy2)) - sin_th = ky / kxy - cos_th = kx / kxy + sin_th = numpy.divide(ky, kxy, out=numpy.zeros_like(ky), where=kxy != 0) + cos_th = numpy.divide(kx, kxy, out=numpy.ones_like(kx), where=kxy != 0) cos_phi = kz / k - sin_th[numpy.logical_and(kx == 0, ky == 0)] = 0 - cos_th[numpy.logical_and(kx == 0, ky == 0)] = 1 - theta = numpy.arctan2(ky, kx) phi = numpy.arccos(cos_phi) theta[numpy.logical_and(kx == 0, ky == 0)] = 0 @@ -205,25 +203,45 @@ def far_to_nearfield( # Normalized vector potentials N, L L = [0.5 * E_far[1], - -0.5 * E_far[0]] # noqa: E128 + -0.5 * E_far[0]] # noqa N = [L[1], - -L[0]] # noqa: E128 + -L[0]] # noqa - En_fft = [-( L[0] * sin_th + L[1] * cos_phi * cos_th) / cos_phi, - -(-L[0] * cos_th + L[1] * cos_phi * sin_th) / cos_phi] + En_fft = [ + numpy.divide( + -(L[0] * sin_th + L[1] * cos_phi * cos_th), + cos_phi, + out=numpy.zeros_like(L[0]), + where=cos_phi != 0, + ), + numpy.divide( + -(-L[0] * cos_th + L[1] * cos_phi * sin_th), + cos_phi, + out=numpy.zeros_like(L[0]), + where=cos_phi != 0, + ), + ] - Hn_fft = [( N[0] * sin_th + N[1] * cos_phi * cos_th) / cos_phi, - (-N[0] * cos_th + N[1] * cos_phi * sin_th) / cos_phi] - - for i in range(2): - En_fft[i][cos_phi == 0] = 0 - Hn_fft[i][cos_phi == 0] = 0 + Hn_fft = [ + numpy.divide( + N[0] * sin_th + N[1] * cos_phi * cos_th, + cos_phi, + out=numpy.zeros_like(N[0]), + where=cos_phi != 0, + ), + numpy.divide( + -N[0] * cos_th + N[1] * cos_phi * sin_th, + cos_phi, + out=numpy.zeros_like(N[0]), + where=cos_phi != 0, + ), + ] E_near = [ifftshift(ifft2(ifftshift(Ei), s=padded_shape)) for Ei in En_fft] H_near = [ifftshift(ifft2(ifftshift(Hi), s=padded_shape)) for Hi in Hn_fft] dx = 2 * pi / (s[0] * dkx) - dy = 2 * pi / (s[0] * dky) + dy = 2 * pi / (s[1] * dky) outputs = { 'E': E_near, @@ -233,4 +251,3 @@ def far_to_nearfield( } return outputs - diff --git a/meanas/fdfd/functional.py b/meanas/fdfd/functional.py index ba2bd70..ddd074b 100644 --- a/meanas/fdfd/functional.py +++ b/meanas/fdfd/functional.py @@ -5,10 +5,10 @@ Functional versions of many FDFD operators. These can be useful for performing The functions generated here expect `cfdfield_t` inputs with shape (3, X, Y, Z), e.g. E = [E_x, E_y, E_z] where each (complex) component has shape (X, Y, Z) """ -from typing import Callable +from collections.abc import Callable import numpy -from ..fdmath import dx_lists_t, fdfield_t, cfdfield_t, cfdfield_updater_t +from ..fdmath import dx_lists_t, cfdfield_t, fdfield, cfdfield, cfdfield_updater_t from ..fdmath.functional import curl_forward, curl_back @@ -18,8 +18,8 @@ __author__ = 'Jan Petykiewicz' def e_full( omega: complex, dxes: dx_lists_t, - epsilon: fdfield_t, - mu: fdfield_t | None = None, + epsilon: fdfield, + mu: fdfield | None = None, ) -> cfdfield_updater_t: """ Wave operator for use with E-field. See `operators.e_full` for details. @@ -37,26 +37,25 @@ def e_full( ch = curl_back(dxes[1]) ce = curl_forward(dxes[0]) - def op_1(e: cfdfield_t) -> cfdfield_t: + def op_1(e: cfdfield) -> cfdfield_t: curls = ch(ce(e)) - return curls - omega ** 2 * epsilon * e + return cfdfield_t(curls - omega ** 2 * epsilon * e) def op_mu(e: cfdfield_t) -> cfdfield_t: - curls = ch(mu * ce(e)) # type: ignore # mu = None ok because we don't return the function - return curls - omega ** 2 * epsilon * e + curls = ch(ce(e) / mu) # type: ignore # mu = None ok because we don't return the function + return cfdfield_t(curls - omega ** 2 * epsilon * e) if mu is None: return op_1 - else: - return op_mu + return op_mu def eh_full( omega: complex, dxes: dx_lists_t, - epsilon: fdfield_t, - mu: fdfield_t | None = None, - ) -> Callable[[cfdfield_t, cfdfield_t], tuple[cfdfield_t, cfdfield_t]]: + epsilon: fdfield, + mu: fdfield | None = None, + ) -> Callable[[cfdfield, cfdfield], tuple[cfdfield_t, cfdfield_t]]: """ Wave operator for full (both E and H) field representation. See `operators.eh_full`. @@ -74,24 +73,23 @@ def eh_full( ch = curl_back(dxes[1]) ce = curl_forward(dxes[0]) - def op_1(e: cfdfield_t, h: cfdfield_t) -> tuple[cfdfield_t, cfdfield_t]: - return (ch(h) - 1j * omega * epsilon * e, - ce(e) + 1j * omega * h) + def op_1(e: cfdfield, h: cfdfield) -> tuple[cfdfield_t, cfdfield_t]: + return (cfdfield_t(ch(h) - 1j * omega * epsilon * e), + cfdfield_t(ce(e) + 1j * omega * h)) - def op_mu(e: cfdfield_t, h: cfdfield_t) -> tuple[cfdfield_t, cfdfield_t]: - return (ch(h) - 1j * omega * epsilon * e, - ce(e) + 1j * omega * mu * h) # type: ignore # mu=None ok + def op_mu(e: cfdfield, h: cfdfield) -> tuple[cfdfield_t, cfdfield_t]: + return (cfdfield_t(ch(h) - 1j * omega * epsilon * e), + cfdfield_t(ce(e) + 1j * omega * mu * h)) # type: ignore # mu=None ok if mu is None: return op_1 - else: - return op_mu + return op_mu def e2h( omega: complex, dxes: dx_lists_t, - mu: fdfield_t | None = None, + mu: fdfield | None = None, ) -> cfdfield_updater_t: """ Utility operator for converting the `E` field into the `H` field. @@ -108,22 +106,21 @@ def e2h( """ ce = curl_forward(dxes[0]) - def e2h_1_1(e: cfdfield_t) -> cfdfield_t: - return ce(e) / (-1j * omega) + def e2h_1_1(e: cfdfield) -> cfdfield_t: + return cfdfield_t(ce(e) / (-1j * omega)) - def e2h_mu(e: cfdfield_t) -> cfdfield_t: - return ce(e) / (-1j * omega * mu) # type: ignore # mu=None ok + def e2h_mu(e: cfdfield) -> cfdfield_t: + return cfdfield_t(ce(e) / (-1j * omega * mu)) # type: ignore # mu=None ok if mu is None: return e2h_1_1 - else: - return e2h_mu + return e2h_mu def m2j( omega: complex, dxes: dx_lists_t, - mu: fdfield_t | None = None, + mu: fdfield | None = None, ) -> cfdfield_updater_t: """ Utility operator for converting magnetic current `M` distribution @@ -142,30 +139,42 @@ def m2j( ch = curl_back(dxes[1]) def m2j_mu(m: cfdfield_t) -> cfdfield_t: - J = ch(m / mu) / (-1j * omega) # type: ignore # mu=None ok - return J + J = ch(m / mu) / (1j * omega) # type: ignore # mu=None ok + return cfdfield_t(J) def m2j_1(m: cfdfield_t) -> cfdfield_t: - J = ch(m) / (-1j * omega) - return J + J = ch(m) / (1j * omega) + return cfdfield_t(J) if mu is None: return m2j_1 - else: - return m2j_mu + return m2j_mu def e_tfsf_source( - TF_region: fdfield_t, + TF_region: fdfield, omega: complex, dxes: dx_lists_t, - epsilon: fdfield_t, - mu: fdfield_t | None = None, + epsilon: fdfield, + mu: fdfield | None = None, ) -> cfdfield_updater_t: - """ + r""" Operator that turns an E-field distribution into a total-field/scattered-field (TFSF) source. + If `A` is the full wave operator from `e_full(...)` and `Q` is the diagonal + mask selecting the total-field region, then the TFSF source is the commutator + + $$ + \frac{A Q - Q A}{-i \omega} E. + $$ + + This vanishes in the interior of the total-field and scattered-field regions + and is supported only at their shared boundary, where the mask discontinuity + makes `A` and `Q` fail to commute. The returned current is therefore the + distributed source needed to inject the desired total field without also + forcing the scattered-field region. + Args: TF_region: mask which is set to 1 in the total-field region, and 0 elsewhere (i.e. in the scattered-field region). @@ -179,20 +188,25 @@ def e_tfsf_source( Function `f` which takes an E field and returns a current distribution, `f(E)` -> `J` """ - # TODO documentation A = e_full(omega, dxes, epsilon, mu) - def op(e: cfdfield_t) -> cfdfield_t: + def op(e: cfdfield) -> cfdfield_t: neg_iwj = A(TF_region * e) - TF_region * A(e) - return neg_iwj / (-1j * omega) + return cfdfield_t(neg_iwj / (-1j * omega)) return op -def poynting_e_cross_h(dxes: dx_lists_t) -> Callable[[cfdfield_t, cfdfield_t], cfdfield_t]: +def poynting_e_cross_h(dxes: dx_lists_t) -> Callable[[cfdfield, cfdfield], cfdfield_t]: r""" Generates a function that takes the single-frequency `E` and `H` fields and calculates the cross product `E` x `H` = $E \times H$ as required - for the Poynting vector, $S = E \times H$ + for the Poynting vector, $S = E \times H$. + + On the Yee grid, the electric and magnetic components are not stored at the + same locations. This helper therefore applies the same one-cell electric-field + shifts used by the sparse `operators.poynting_e_cross(...)` construction so + that the discrete cross product matches the face-centered energy flux used in + `meanas.fdtd.energy.poynting(...)`. Note: This function also shifts the input `E` field by one cell as required @@ -208,9 +222,10 @@ def poynting_e_cross_h(dxes: dx_lists_t) -> Callable[[cfdfield_t, cfdfield_t], c dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` Returns: - Function `f` that returns E x H as required for the poynting vector. + Function `f` that returns the staggered-grid cross product `E \times H`. + For time-average power, call it as `f(E, H.conj())` and take `Re(...) / 2`. """ - def exh(e: cfdfield_t, h: cfdfield_t) -> cfdfield_t: + def exh(e: cfdfield, h: cfdfield) -> cfdfield_t: s = numpy.empty_like(e) ex = e[0] * dxes[0][0][:, None, None] ey = e[1] * dxes[0][1][None, :, None] @@ -221,5 +236,5 @@ def poynting_e_cross_h(dxes: dx_lists_t) -> Callable[[cfdfield_t, cfdfield_t], c s[0] = numpy.roll(ey, -1, axis=0) * hz - numpy.roll(ez, -1, axis=0) * hy s[1] = numpy.roll(ez, -1, axis=1) * hx - numpy.roll(ex, -1, axis=1) * hz s[2] = numpy.roll(ex, -1, axis=2) * hy - numpy.roll(ey, -1, axis=2) * hx - return s + return cfdfield_t(s) return exh diff --git a/meanas/fdfd/operators.py b/meanas/fdfd/operators.py index 3a489a7..6425a29 100644 --- a/meanas/fdfd/operators.py +++ b/meanas/fdfd/operators.py @@ -1,7 +1,7 @@ """ Sparse matrix operators for use with electromagnetic wave equations. -These functions return sparse-matrix (`scipy.sparse.spmatrix`) representations of +These functions return sparse-matrix (`scipy.sparse.sparray`) representations of a variety of operators, intended for use with E and H fields vectorized using the `meanas.fdmath.vectorization.vec()` and `meanas.fdmath.vectorization.unvec()` functions. @@ -28,9 +28,9 @@ The following operators are included: """ import numpy -import scipy.sparse as sparse # type: ignore +from scipy import sparse -from ..fdmath import vec, dx_lists_t, vfdfield_t, vcfdfield_t +from ..fdmath import vec, dx_lists_t, vfdfield, vcfdfield from ..fdmath.operators import shift_with_mirror, shift_circ, curl_forward, curl_back @@ -40,11 +40,11 @@ __author__ = 'Jan Petykiewicz' def e_full( omega: complex, dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - pec: vfdfield_t | None = None, - pmc: vfdfield_t | None = None, - ) -> sparse.spmatrix: + epsilon: vfdfield | vcfdfield, + mu: vfdfield | None = None, + pec: vfdfield | None = None, + pmc: vfdfield | None = None, + ) -> sparse.sparray: r""" Wave operator $$ \nabla \times (\frac{1}{\mu} \nabla \times) - \Omega^2 \epsilon $$ @@ -64,11 +64,11 @@ def e_full( epsilon: Vectorized dielectric constant mu: Vectorized magnetic permeability (default 1 everywhere). pec: Vectorized mask specifying PEC cells. Any cells where `pec != 0` are interpreted - as containing a perfect electrical conductor (PEC). - The PEC is applied per-field-component (i.e. `pec.size == epsilon.size`) + as containing a perfect electrical conductor (PEC). + The PEC is applied per-field-component (i.e. `pec.size == epsilon.size`) pmc: Vectorized mask specifying PMC cells. Any cells where `pmc != 0` are interpreted - as containing a perfect magnetic conductor (PMC). - The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) + as containing a perfect magnetic conductor (PMC). + The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) Returns: Sparse matrix containing the wave operator. @@ -77,20 +77,20 @@ def e_full( ce = curl_forward(dxes[0]) if pec is None: - pe = sparse.eye(epsilon.size) + pe = sparse.eye_array(epsilon.size) else: - pe = sparse.diags(numpy.where(pec, 0, 1)) # Set pe to (not PEC) + pe = sparse.diags_array(numpy.where(pec, 0, 1)) # Set pe to (not PEC) if pmc is None: - pm = sparse.eye(epsilon.size) + pm = sparse.eye_array(epsilon.size) else: - pm = sparse.diags(numpy.where(pmc, 0, 1)) # set pm to (not PMC) + pm = sparse.diags_array(numpy.where(pmc, 0, 1)) # set pm to (not PMC) - e = sparse.diags(epsilon) + e = sparse.diags_array(epsilon) if mu is None: - m_div = sparse.eye(epsilon.size) + m_div = sparse.eye_array(epsilon.size) else: - m_div = sparse.diags(1 / mu) + m_div = sparse.diags_array(1 / mu) op = pe @ (ch @ pm @ m_div @ ce - omega**2 * e) @ pe return op @@ -98,7 +98,7 @@ def e_full( def e_full_preconditioners( dxes: dx_lists_t, - ) -> tuple[sparse.spmatrix, sparse.spmatrix]: + ) -> tuple[sparse.sparray, sparse.sparray]: """ Left and right preconditioners `(Pl, Pr)` for symmetrizing the `e_full` wave operator. @@ -118,19 +118,19 @@ def e_full_preconditioners( dxes[1][0][:, None, None] * dxes[1][1][None, :, None] * dxes[0][2][None, None, :]] p_vector = numpy.sqrt(vec(p_squared)) - P_left = sparse.diags(p_vector) - P_right = sparse.diags(1 / p_vector) + P_left = sparse.diags_array(p_vector) + P_right = sparse.diags_array(1 / p_vector) return P_left, P_right def h_full( omega: complex, dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - pec: vfdfield_t | None = None, - pmc: vfdfield_t | None = None, - ) -> sparse.spmatrix: + epsilon: vfdfield, + mu: vfdfield | None = None, + pec: vfdfield | None = None, + pmc: vfdfield | None = None, + ) -> sparse.sparray: r""" Wave operator $$ \nabla \times (\frac{1}{\epsilon} \nabla \times) - \omega^2 \mu $$ @@ -148,11 +148,11 @@ def h_full( epsilon: Vectorized dielectric constant mu: Vectorized magnetic permeability (default 1 everywhere) pec: Vectorized mask specifying PEC cells. Any cells where `pec != 0` are interpreted - as containing a perfect electrical conductor (PEC). - The PEC is applied per-field-component (i.e. `pec.size == epsilon.size`) + as containing a perfect electrical conductor (PEC). + The PEC is applied per-field-component (i.e. `pec.size == epsilon.size`) pmc: Vectorized mask specifying PMC cells. Any cells where `pmc != 0` are interpreted - as containing a perfect magnetic conductor (PMC). - The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) + as containing a perfect magnetic conductor (PMC). + The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) Returns: Sparse matrix containing the wave operator. @@ -161,20 +161,20 @@ def h_full( ce = curl_forward(dxes[0]) if pec is None: - pe = sparse.eye(epsilon.size) + pe = sparse.eye_array(epsilon.size) else: - pe = sparse.diags(numpy.where(pec, 0, 1)) # set pe to (not PEC) + pe = sparse.diags_array(numpy.where(pec, 0, 1)) # set pe to (not PEC) if pmc is None: - pm = sparse.eye(epsilon.size) + pm = sparse.eye_array(epsilon.size) else: - pm = sparse.diags(numpy.where(pmc, 0, 1)) # Set pe to (not PMC) + pm = sparse.diags_array(numpy.where(pmc, 0, 1)) # Set pe to (not PMC) - e_div = sparse.diags(1 / epsilon) + e_div = sparse.diags_array(1 / epsilon) if mu is None: - m = sparse.eye(epsilon.size) + m = sparse.eye_array(epsilon.size) else: - m = sparse.diags(mu) + m = sparse.diags_array(mu) A = pm @ (ce @ pe @ e_div @ ch - omega**2 * m) @ pm return A @@ -183,11 +183,11 @@ def h_full( def eh_full( omega: complex, dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - pec: vfdfield_t | None = None, - pmc: vfdfield_t | None = None, - ) -> sparse.spmatrix: + epsilon: vfdfield, + mu: vfdfield | None = None, + pec: vfdfield | None = None, + pmc: vfdfield | None = None, + ) -> sparse.sparray: r""" Wave operator for `[E, H]` field representation. This operator implements Maxwell's equations without cancelling out either E or H. The operator is @@ -217,45 +217,47 @@ def eh_full( epsilon: Vectorized dielectric constant mu: Vectorized magnetic permeability (default 1 everywhere) pec: Vectorized mask specifying PEC cells. Any cells where `pec != 0` are interpreted - as containing a perfect electrical conductor (PEC). - The PEC is applied per-field-component (i.e. `pec.size == epsilon.size`) + as containing a perfect electrical conductor (PEC). + The PEC is applied per-field-component (i.e. `pec.size == epsilon.size`) pmc: Vectorized mask specifying PMC cells. Any cells where `pmc != 0` are interpreted - as containing a perfect magnetic conductor (PMC). - The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) + as containing a perfect magnetic conductor (PMC). + The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) Returns: Sparse matrix containing the wave operator. """ if pec is None: - pe = sparse.eye(epsilon.size) + pe = sparse.eye_array(epsilon.size) else: - pe = sparse.diags(numpy.where(pec, 0, 1)) # set pe to (not PEC) + pe = sparse.diags_array(numpy.where(pec, 0, 1)) # set pe to (not PEC) if pmc is None: - pm = sparse.eye(epsilon.size) + pm = sparse.eye_array(epsilon.size) else: - pm = sparse.diags(numpy.where(pmc, 0, 1)) # set pm to (not PMC) + pm = sparse.diags_array(numpy.where(pmc, 0, 1)) # set pm to (not PMC) iwe = pe @ (1j * omega * sparse.diags(epsilon)) @ pe - iwm = 1j * omega - if mu is not None: - iwm *= sparse.diags(mu) + if mu is None: + iwm = 1j * omega * sparse.eye(epsilon.size) + else: + iwm = 1j * omega * sparse.diags(mu) + iwm = pm @ iwm @ pm A1 = pe @ curl_back(dxes[1]) @ pm A2 = pm @ curl_forward(dxes[0]) @ pe - A = sparse.bmat([[-iwe, A1], - [A2, iwm]]) + A = sparse.block_array([[-iwe, A1], + [A2, iwm]]) return A def e2h( omega: complex, dxes: dx_lists_t, - mu: vfdfield_t | None = None, - pmc: vfdfield_t | None = None, - ) -> sparse.spmatrix: + mu: vfdfield | None = None, + pmc: vfdfield | None = None, + ) -> sparse.sparray: """ Utility operator for converting the E field into the H field. For use with `e_full()` -- assumes that there is no magnetic current M. @@ -265,8 +267,8 @@ def e2h( dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` mu: Vectorized magnetic permeability (default 1 everywhere) pmc: Vectorized mask specifying PMC cells. Any cells where `pmc != 0` are interpreted - as containing a perfect magnetic conductor (PMC). - The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) + as containing a perfect magnetic conductor (PMC). + The PMC is applied per-field-component (i.e. `pmc.size == epsilon.size`) Returns: Sparse matrix for converting E to H. @@ -274,10 +276,10 @@ def e2h( op = curl_forward(dxes[0]) / (-1j * omega) if mu is not None: - op = sparse.diags(1 / mu) @ op + op = sparse.diags_array(1 / mu) @ op if pmc is not None: - op = sparse.diags(numpy.where(pmc, 0, 1)) @ op + op = sparse.diags_array(numpy.where(pmc, 0, 1)) @ op return op @@ -285,8 +287,8 @@ def e2h( def m2j( omega: complex, dxes: dx_lists_t, - mu: vfdfield_t | None = None, - ) -> sparse.spmatrix: + mu: vfdfield | None = None, + ) -> sparse.sparray: """ Operator for converting a magnetic current M into an electric current J. For use with eg. `e_full()`. @@ -302,79 +304,108 @@ def m2j( op = curl_back(dxes[1]) / (1j * omega) if mu is not None: - op = op @ sparse.diags(1 / mu) + op = op @ sparse.diags_array(1 / mu) return op -def poynting_e_cross(e: vcfdfield_t, dxes: dx_lists_t) -> sparse.spmatrix: - """ - Operator for computing the Poynting vector, containing the - (E x) portion of the Poynting vector. +def poynting_e_cross(e: vcfdfield, dxes: dx_lists_t) -> sparse.sparray: + r""" + Operator for computing the staggered-grid `(E \times)` part of the Poynting vector. + + On the Yee grid the E and H components live on different edges, so the + electric field must be shifted by one cell in the appropriate direction + before forming the discrete cross product. This sparse operator encodes that + shifted cross product directly and is the matrix equivalent of + `functional.poynting_e_cross_h(...)`. Args: e: Vectorized E-field for the ExH cross product dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` Returns: - Sparse matrix containing (E x) portion of Poynting cross product. + Sparse matrix containing the `(E \times)` part of the staggered Poynting + cross product. """ shape = [len(dx) for dx in dxes[0]] - fx, fy, fz = [shift_circ(i, shape, 1) for i in range(3)] + fx, fy, fz = (shift_circ(i, shape, 1) for i in range(3)) dxag = [dx.ravel(order='C') for dx in numpy.meshgrid(*dxes[0], indexing='ij')] dxbg = [dx.ravel(order='C') for dx in numpy.meshgrid(*dxes[1], indexing='ij')] - Ex, Ey, Ez = [ei * da for ei, da in zip(numpy.split(e, 3), dxag)] + Ex, Ey, Ez = (ei * da for ei, da in zip(numpy.split(e, 3), dxag, strict=True)) block_diags = [[ None, fx @ -Ez, fx @ Ey], [ fy @ Ez, None, fy @ -Ex], [ fz @ -Ey, fz @ Ex, None]] - block_matrix = sparse.bmat([[sparse.diags(x) if x is not None else None for x in row] - for row in block_diags]) - P = block_matrix @ sparse.diags(numpy.concatenate(dxbg)) + block_matrix = sparse.block_array([[sparse.diags_array(x) if x is not None else None for x in row] + for row in block_diags]) + P = block_matrix @ sparse.diags_array(numpy.concatenate(dxbg)) return P -def poynting_h_cross(h: vcfdfield_t, dxes: dx_lists_t) -> sparse.spmatrix: - """ - Operator for computing the Poynting vector, containing the (H x) portion of the Poynting vector. +def poynting_h_cross(h: vcfdfield, dxes: dx_lists_t) -> sparse.sparray: + r""" + Operator for computing the staggered-grid `(H \times)` part of the Poynting vector. + + Together with `poynting_e_cross(...)`, this provides the matrix form of the + Yee-grid cross product used in the flux helpers. The two are related by the + usual antisymmetry of the cross product, + + $$ + H \times E = -(E \times H), + $$ + + once the same staggered field placement is used on both sides. Args: h: Vectorized H-field for the HxE cross product dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` Returns: - Sparse matrix containing (H x) portion of Poynting cross product. + Sparse matrix containing the `(H \times)` part of the staggered Poynting + cross product. """ shape = [len(dx) for dx in dxes[0]] - fx, fy, fz = [shift_circ(i, shape, 1) for i in range(3)] + fx, fy, fz = (shift_circ(i, shape, 1) for i in range(3)) dxag = [dx.ravel(order='C') for dx in numpy.meshgrid(*dxes[0], indexing='ij')] dxbg = [dx.ravel(order='C') for dx in numpy.meshgrid(*dxes[1], indexing='ij')] - Hx, Hy, Hz = [sparse.diags(hi * db) for hi, db in zip(numpy.split(h, 3), dxbg)] + Hx, Hy, Hz = (sparse.diags_array(hi * db) for hi, db in zip(numpy.split(h, 3), dxbg, strict=True)) - P = (sparse.bmat( + P = (sparse.block_array( [[ None, -Hz @ fx, Hy @ fx], [ Hz @ fy, None, -Hx @ fy], [-Hy @ fz, Hx @ fz, None]]) - @ sparse.diags(numpy.concatenate(dxag))) + @ sparse.diags_array(numpy.concatenate(dxag))) return P def e_tfsf_source( - TF_region: vfdfield_t, + TF_region: vfdfield, omega: complex, dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - ) -> sparse.spmatrix: - """ + epsilon: vfdfield, + mu: vfdfield | None = None, + ) -> sparse.sparray: + r""" Operator that turns a desired E-field distribution into a total-field/scattered-field (TFSF) source. - TODO: Reference Rumpf paper + Let `A` be the full wave operator from `e_full(...)`, and let + `Q = \mathrm{diag}(TF_region)` be the projector onto the total-field region. + Then the TFSF current operator is the commutator + + $$ + \frac{A Q - Q A}{-i \omega}. + $$ + + Inside regions where `Q` is locally constant, `A` and `Q` commute and the + source vanishes. Only cells at the TF/SF boundary contribute nonzero current, + which is exactly the desired distributed source for injecting the chosen + field into the total-field region without directly forcing the + scattered-field region. Args: TF_region: Mask, which is set to 1 inside the total-field region and 0 in the @@ -386,27 +417,31 @@ def e_tfsf_source( Returns: Sparse matrix that turns an E-field into a current (J) distribution. - """ - # TODO documentation A = e_full(omega, dxes, epsilon, mu) - Q = sparse.diags(TF_region) + Q = sparse.diags_array(TF_region) return (A @ Q - Q @ A) / (-1j * omega) def e_boundary_source( - mask: vfdfield_t, + mask: vfdfield, omega: complex, dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, + epsilon: vfdfield, + mu: vfdfield | None = None, periodic_mask_edges: bool = False, - ) -> sparse.spmatrix: - """ + ) -> sparse.sparray: + r""" Operator that turns an E-field distrubtion into a current (J) distribution along the edges (external and internal) of the provided mask. This is just an `e_tfsf_source()` with an additional masking step. + Equivalently, this helper first constructs the TFSF commutator source for the + full mask and then zeroes out all cells except the mask boundary. The + boundary is defined as the set of cells whose mask value changes under a + one-cell shift in any Cartesian direction. With `periodic_mask_edges=False` + the shifts mirror at the domain boundary; with `True` they wrap periodically. + Args: mask: The current distribution is generated at the edges of the mask, i.e. any points where shifting the mask by one cell in any direction @@ -424,10 +459,10 @@ def e_boundary_source( shape = [len(dxe) for dxe in dxes[0]] jmask = numpy.zeros_like(mask, dtype=bool) - def shift_rot(axis: int, polarity: int) -> sparse.spmatrix: + def shift_rot(axis: int, polarity: int) -> sparse.sparray: return shift_circ(axis=axis, shape=shape, shift_distance=polarity) - def shift_mir(axis: int, polarity: int) -> sparse.spmatrix: + def shift_mir(axis: int, polarity: int) -> sparse.sparray: return shift_with_mirror(axis=axis, shape=shape, shift_distance=polarity) shift = shift_rot if periodic_mask_edges else shift_mir @@ -436,7 +471,7 @@ def e_boundary_source( if shape[axis] == 1: continue for polarity in (-1, +1): - r = shift(axis, polarity) - sparse.eye(numpy.prod(shape)) # shifted minus original + r = shift(axis, polarity) - sparse.eye_array(numpy.prod(shape)) # shifted minus original r3 = sparse.block_diag((r, r, r)) jmask = numpy.logical_or(jmask, numpy.abs(r3 @ mask)) @@ -447,5 +482,4 @@ def e_boundary_source( # (numpy.roll(mask, -1, axis=2) != mask) | # (numpy.roll(mask, +1, axis=2) != mask)) - return sparse.diags(jmask.astype(int)) @ full - + return sparse.diags_array(jmask.astype(int)) @ full diff --git a/meanas/fdfd/scpml.py b/meanas/fdfd/scpml.py index bc056e1..7030876 100644 --- a/meanas/fdfd/scpml.py +++ b/meanas/fdfd/scpml.py @@ -2,7 +2,7 @@ Functions for creating stretched coordinate perfectly matched layer (PML) absorbers. """ -from typing import Sequence, Callable +from collections.abc import Sequence, Callable import numpy from numpy.typing import NDArray @@ -128,6 +128,11 @@ def stretch_with_scpml( dx_ai = dxes[0][axis].astype(complex) dx_bi = dxes[1][axis].astype(complex) + if thickness == 0: + dxes[0][axis] = dx_ai + dxes[1][axis] = dx_bi + return dxes + pos = numpy.hstack((0, dx_ai.cumsum())) pos_a = (pos[:-1] + pos[1:]) / 2 pos_b = pos[:-1] @@ -153,10 +158,7 @@ def stretch_with_scpml( def l_d(x: NDArray[numpy.float64]) -> NDArray[numpy.float64]: return (x - bound) / (pos[-1] - bound) - if thickness == 0: - slc = slice(None) - else: - slc = slice(-thickness, None) + slc = slice(-thickness, None) dx_ai[slc] *= 1 + 1j * s_function(l_d(pos_a[slc])) / d / s_correction dx_bi[slc] *= 1 + 1j * s_function(l_d(pos_b[slc])) / d / s_correction diff --git a/meanas/fdfd/solvers.py b/meanas/fdfd/solvers.py index 8ac157c..e1f394c 100644 --- a/meanas/fdfd/solvers.py +++ b/meanas/fdfd/solvers.py @@ -2,15 +2,16 @@ Solvers and solver interface for FDFD problems. """ -from typing import Callable, Dict, Any, Optional +from typing import Any +from collections.abc import Callable import logging import numpy from numpy.typing import ArrayLike, NDArray from numpy.linalg import norm -import scipy.sparse.linalg # type: ignore +import scipy.sparse.linalg -from ..fdmath import dx_lists_t, vfdfield_t, vcfdfield_t +from ..fdmath import dx_lists_t, vfdfield, vcfdfield, vcfdfield_t from . import operators @@ -18,7 +19,7 @@ logger = logging.getLogger(__name__) def _scipy_qmr( - A: scipy.sparse.csr_matrix, + A: scipy.sparse.csr_array, b: ArrayLike, **kwargs: Any, ) -> NDArray[numpy.float64]: @@ -34,31 +35,32 @@ def _scipy_qmr( Guess for solution (returned even if didn't converge) """ - ''' - Report on our progress - ''' + # + #Report on our progress + # ii = 0 def log_residual(xk: ArrayLike) -> None: nonlocal ii ii += 1 if ii % 100 == 0: - cur_norm = norm(A @ xk - b) + cur_norm = norm(A @ xk - b) / norm(b) logger.info(f'Solver residual at iteration {ii} : {cur_norm}') if 'callback' in kwargs: + callback = kwargs['callback'] + def augmented_callback(xk: ArrayLike) -> None: log_residual(xk) - kwargs['callback'](xk) + callback(xk) kwargs['callback'] = augmented_callback else: kwargs['callback'] = log_residual - ''' - Run the actual solve - ''' - + # + # Run the actual solve + # x, _ = scipy.sparse.linalg.qmr(A, b, **kwargs) return x @@ -66,14 +68,16 @@ def _scipy_qmr( def generic( omega: complex, dxes: dx_lists_t, - J: vcfdfield_t, - epsilon: vfdfield_t, - mu: Optional[vfdfield_t] = None, - pec: Optional[vfdfield_t] = None, - pmc: Optional[vfdfield_t] = None, + J: vcfdfield, + epsilon: vfdfield, + mu: vfdfield | None = None, + *, + pec: vfdfield | None = None, + pmc: vfdfield | None = None, adjoint: bool = False, matrix_solver: Callable[..., ArrayLike] = _scipy_qmr, - matrix_solver_opts: Optional[Dict[str, Any]] = None, + matrix_solver_opts: dict[str, Any] | None = None, + E_guess: vcfdfield | None = None, ) -> vcfdfield_t: """ Conjugate gradient FDFD solver using CSR sparse matrices. @@ -93,13 +97,15 @@ def generic( (at H-field locations; non-zero value indicates PMC is present) adjoint: If true, solves the adjoint problem. matrix_solver: Called as `matrix_solver(A, b, **matrix_solver_opts) -> x`, - where `A`: `scipy.sparse.csr_matrix`; + where `A`: `scipy.sparse.csr_array`; `b`: `ArrayLike`; `x`: `ArrayLike`; Default is a wrapped version of `scipy.sparse.linalg.qmr()` which doesn't return convergence info and logs the residual every 100 iterations. matrix_solver_opts: Passed as kwargs to `matrix_solver(...)` + E_guess: Guess at the solution E-field. `matrix_solver` must accept an + `x0` argument with the same purpose. Returns: E-field which solves the system. @@ -114,17 +120,24 @@ def generic( Pl, Pr = operators.e_full_preconditioners(dxes) if adjoint: - A = (Pl @ A0 @ Pr).H - b = Pr.H @ b0 + A = (Pl @ A0 @ Pr).T.conjugate() + b = Pr.T.conjugate() @ b0 else: A = Pl @ A0 @ Pr b = Pl @ b0 + if E_guess is not None: + if adjoint: + x0 = Pr.T.conjugate() @ E_guess + else: + x0 = Pl @ E_guess + matrix_solver_opts['x0'] = x0 + x = matrix_solver(A.tocsr(), b, **matrix_solver_opts) if adjoint: - x0 = Pl.H @ x + x0 = Pl.T.conjugate() @ x else: x0 = Pr @ x - return x0 + return vcfdfield_t(x0) diff --git a/meanas/fdfd/waveguide_2d.py b/meanas/fdfd/waveguide_2d.py index 399574d..e67160e 100644 --- a/meanas/fdfd/waveguide_2d.py +++ b/meanas/fdfd/waveguide_2d.py @@ -18,8 +18,8 @@ $$ \begin{aligned} \nabla \times \vec{E}(x, y, z) &= -\imath \omega \mu \vec{H} \\ \nabla \times \vec{H}(x, y, z) &= \imath \omega \epsilon \vec{E} \\ -\vec{E}(x,y,z) &= (\vec{E}_t(x, y) + E_z(x, y)\vec{z}) e^{-\gamma z} \\ -\vec{H}(x,y,z) &= (\vec{H}_t(x, y) + H_z(x, y)\vec{z}) e^{-\gamma z} \\ +\vec{E}(x,y,z) &= (\vec{E}_t(x, y) + E_z(x, y)\vec{z}) e^{-\imath \beta z} \\ +\vec{H}(x,y,z) &= (\vec{H}_t(x, y) + H_z(x, y)\vec{z}) e^{-\imath \beta z} \\ \end{aligned} $$ @@ -40,56 +40,57 @@ Substituting in our expressions for $\vec{E}$, $\vec{H}$ and discretizing: $$ \begin{aligned} --\imath \omega \mu_{xx} H_x &= \tilde{\partial}_y E_z + \gamma E_y \\ --\imath \omega \mu_{yy} H_y &= -\gamma E_x - \tilde{\partial}_x E_z \\ +-\imath \omega \mu_{xx} H_x &= \tilde{\partial}_y E_z + \imath \beta E_y \\ +-\imath \omega \mu_{yy} H_y &= -\imath \beta E_x - \tilde{\partial}_x E_z \\ -\imath \omega \mu_{zz} H_z &= \tilde{\partial}_x E_y - \tilde{\partial}_y E_x \\ -\imath \omega \epsilon_{xx} E_x &= \hat{\partial}_y H_z + \gamma H_y \\ -\imath \omega \epsilon_{yy} E_y &= -\gamma H_x - \hat{\partial}_x H_z \\ +\imath \omega \epsilon_{xx} E_x &= \hat{\partial}_y H_z + \imath \beta H_y \\ +\imath \omega \epsilon_{yy} E_y &= -\imath \beta H_x - \hat{\partial}_x H_z \\ \imath \omega \epsilon_{zz} E_z &= \hat{\partial}_x H_y - \hat{\partial}_y H_x \\ \end{aligned} $$ Rewrite the last three equations as + $$ \begin{aligned} -\gamma H_y &= \imath \omega \epsilon_{xx} E_x - \hat{\partial}_y H_z \\ -\gamma H_x &= -\imath \omega \epsilon_{yy} E_y - \hat{\partial}_x H_z \\ +\imath \beta H_y &= \imath \omega \epsilon_{xx} E_x - \hat{\partial}_y H_z \\ +\imath \beta H_x &= -\imath \omega \epsilon_{yy} E_y - \hat{\partial}_x H_z \\ \imath \omega E_z &= \frac{1}{\epsilon_{zz}} \hat{\partial}_x H_y - \frac{1}{\epsilon_{zz}} \hat{\partial}_y H_x \\ \end{aligned} $$ -Now apply $\gamma \tilde{\partial}_x$ to the last equation, -then substitute in for $\gamma H_x$ and $\gamma H_y$: +Now apply $\imath \beta \tilde{\partial}_x$ to the last equation, +then substitute in for $\imath \beta H_x$ and $\imath \beta H_y$: $$ \begin{aligned} -\gamma \tilde{\partial}_x \imath \omega E_z &= \gamma \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_x H_y - - \gamma \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_y H_x \\ +\imath \beta \tilde{\partial}_x \imath \omega E_z &= \imath \beta \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_x H_y + - \imath \beta \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_y H_x \\ &= \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_x ( \imath \omega \epsilon_{xx} E_x - \hat{\partial}_y H_z) - \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_y (-\imath \omega \epsilon_{yy} E_y - \hat{\partial}_x H_z) \\ &= \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_x ( \imath \omega \epsilon_{xx} E_x) - \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_y (-\imath \omega \epsilon_{yy} E_y) \\ -\gamma \tilde{\partial}_x E_z &= \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) - + \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) \\ +\imath \beta \tilde{\partial}_x E_z &= \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) + + \tilde{\partial}_x \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) \\ \end{aligned} $$ -With a similar approach (but using $\gamma \tilde{\partial}_y$ instead), we can get +With a similar approach (but using $\imath \beta \tilde{\partial}_y$ instead), we can get $$ \begin{aligned} -\gamma \tilde{\partial}_y E_z &= \tilde{\partial}_y \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) - + \tilde{\partial}_y \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) \\ +\imath \beta \tilde{\partial}_y E_z &= \tilde{\partial}_y \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) + + \tilde{\partial}_y \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) \\ \end{aligned} $$ -We can combine this equation for $\gamma \tilde{\partial}_y E_z$ with +We can combine this equation for $\imath \beta \tilde{\partial}_y E_z$ with the unused $\imath \omega \mu_{xx} H_x$ and $\imath \omega \mu_{yy} H_y$ equations to get $$ \begin{aligned} --\imath \omega \mu_{xx} \gamma H_x &= \gamma^2 E_y + \gamma \tilde{\partial}_y E_z \\ --\imath \omega \mu_{xx} \gamma H_x &= \gamma^2 E_y + \tilde{\partial}_y ( +-\imath \omega \mu_{xx} \imath \beta H_x &= -\beta^2 E_y + \imath \beta \tilde{\partial}_y E_z \\ +-\imath \omega \mu_{xx} \imath \beta H_x &= -\beta^2 E_y + \tilde{\partial}_y ( \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) + \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) )\\ @@ -100,25 +101,24 @@ and $$ \begin{aligned} --\imath \omega \mu_{yy} \gamma H_y &= -\gamma^2 E_x - \gamma \tilde{\partial}_x E_z \\ --\imath \omega \mu_{yy} \gamma H_y &= -\gamma^2 E_x - \tilde{\partial}_x ( +-\imath \omega \mu_{yy} \imath \beta H_y &= \beta^2 E_x - \imath \beta \tilde{\partial}_x E_z \\ +-\imath \omega \mu_{yy} \imath \beta H_y &= \beta^2 E_x - \tilde{\partial}_x ( \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) + \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) )\\ \end{aligned} $$ -However, based on our rewritten equation for $\gamma H_x$ and the so-far unused +However, based on our rewritten equation for $\imath \beta H_x$ and the so-far unused equation for $\imath \omega \mu_{zz} H_z$ we can also write $$ \begin{aligned} --\imath \omega \mu_{xx} (\gamma H_x) &= -\imath \omega \mu_{xx} (-\imath \omega \epsilon_{yy} E_y - \hat{\partial}_x H_z) \\ - &= -\omega^2 \mu_{xx} \epsilon_{yy} E_y - +\imath \omega \mu_{xx} \hat{\partial}_x ( - \frac{1}{-\imath \omega \mu_{zz}} (\tilde{\partial}_x E_y - \tilde{\partial}_y E_x)) \\ - &= -\omega^2 \mu_{xx} \epsilon_{yy} E_y - -\mu_{xx} \hat{\partial}_x \frac{1}{\mu_{zz}} (\tilde{\partial}_x E_y - \tilde{\partial}_y E_x) \\ +-\imath \omega \mu_{xx} (\imath \beta H_x) &= -\imath \omega \mu_{xx} (-\imath \omega \epsilon_{yy} E_y - \hat{\partial}_x H_z) \\ + &= -\omega^2 \mu_{xx} \epsilon_{yy} E_y + \imath \omega \mu_{xx} \hat{\partial}_x ( + \frac{1}{-\imath \omega \mu_{zz}} (\tilde{\partial}_x E_y - \tilde{\partial}_y E_x)) \\ + &= -\omega^2 \mu_{xx} \epsilon_{yy} E_y + -\mu_{xx} \hat{\partial}_x \frac{1}{\mu_{zz}} (\tilde{\partial}_x E_y - \tilde{\partial}_y E_x) \\ \end{aligned} $$ @@ -126,7 +126,7 @@ and, similarly, $$ \begin{aligned} --\imath \omega \mu_{yy} (\gamma H_y) &= \omega^2 \mu_{yy} \epsilon_{xx} E_x +-\imath \omega \mu_{yy} (\imath \beta H_y) &= \omega^2 \mu_{yy} \epsilon_{xx} E_x +\mu_{yy} \hat{\partial}_y \frac{1}{\mu_{zz}} (\tilde{\partial}_x E_y - \tilde{\partial}_y E_x) \\ \end{aligned} $$ @@ -135,12 +135,12 @@ By combining both pairs of expressions, we get $$ \begin{aligned} --\gamma^2 E_x - \tilde{\partial}_x ( +\beta^2 E_x - \tilde{\partial}_x ( \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) + \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) ) &= \omega^2 \mu_{yy} \epsilon_{xx} E_x +\mu_{yy} \hat{\partial}_y \frac{1}{\mu_{zz}} (\tilde{\partial}_x E_y - \tilde{\partial}_y E_x) \\ -\gamma^2 E_y + \tilde{\partial}_y ( +-\beta^2 E_y + \tilde{\partial}_y ( \frac{1}{\epsilon_{zz}} \hat{\partial}_x (\epsilon_{xx} E_x) + \frac{1}{\epsilon_{zz}} \hat{\partial}_y (\epsilon_{yy} E_y) ) &= -\omega^2 \mu_{xx} \epsilon_{yy} E_y @@ -165,27 +165,25 @@ $$ E_y \end{bmatrix} $$ -where $\gamma = \imath\beta$. In the literature, $\beta$ is usually used to denote -the lossless/real part of the propagation constant, but in `meanas` it is allowed to -be complex. +In the literature, $\beta$ is usually used to denote the lossless/real part of the propagation constant, +but in `meanas` it is allowed to be complex. An equivalent eigenvalue problem can be formed using the $H_x$ and $H_y$ fields, if those are more convenient. -Note that $E_z$ was never discretized, so $\gamma$ and $\beta$ will need adjustment -to account for numerical dispersion if the result is introduced into a space with a discretized z-axis. +Note that $E_z$ was never discretized, so $\beta$ will need adjustment to account for numerical dispersion +if the result is introduced into a space with a discretized z-axis. """ -# TODO update module docs - from typing import Any +from collections.abc import Sequence import numpy -from numpy.typing import NDArray, ArrayLike +from numpy.typing import NDArray from numpy.linalg import norm -import scipy.sparse as sparse # type: ignore +from scipy import sparse from ..fdmath.operators import deriv_forward, deriv_back, cross -from ..fdmath import vec, unvec, dx_lists_t, vfdfield_t, vcfdfield_t +from ..fdmath import vec, unvec, dx_lists2_t, vcfdfield2_t, vcfdslice_t, vcfdfield2, vfdslice, vcfdslice from ..eigensolvers import signed_eigensolve, rayleigh_quotient_iteration @@ -194,10 +192,10 @@ __author__ = 'Jan Petykiewicz' def operator_e( omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, + ) -> sparse.sparray: r""" Waveguide operator of the form @@ -246,12 +244,12 @@ def operator_e( Dbx, Dby = deriv_back(dxes[1]) eps_parts = numpy.split(epsilon, 3) - eps_xy = sparse.diags(numpy.hstack((eps_parts[0], eps_parts[1]))) - eps_z_inv = sparse.diags(1 / eps_parts[2]) + eps_xy = sparse.diags_array(numpy.hstack((eps_parts[0], eps_parts[1]))) + eps_z_inv = sparse.diags_array(1 / eps_parts[2]) mu_parts = numpy.split(mu, 3) - mu_yx = sparse.diags(numpy.hstack((mu_parts[1], mu_parts[0]))) - mu_z_inv = sparse.diags(1 / mu_parts[2]) + mu_yx = sparse.diags_array(numpy.hstack((mu_parts[1], mu_parts[0]))) + mu_z_inv = sparse.diags_array(1 / mu_parts[2]) op = ( omega * omega * mu_yx @ eps_xy @@ -263,10 +261,10 @@ def operator_e( def operator_h( omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, + ) -> sparse.sparray: r""" Waveguide operator of the form @@ -315,12 +313,12 @@ def operator_h( Dbx, Dby = deriv_back(dxes[1]) eps_parts = numpy.split(epsilon, 3) - eps_yx = sparse.diags(numpy.hstack((eps_parts[1], eps_parts[0]))) - eps_z_inv = sparse.diags(1 / eps_parts[2]) + eps_yx = sparse.diags_array(numpy.hstack((eps_parts[1], eps_parts[0]))) + eps_z_inv = sparse.diags_array(1 / eps_parts[2]) mu_parts = numpy.split(mu, 3) - mu_xy = sparse.diags(numpy.hstack((mu_parts[0], mu_parts[1]))) - mu_z_inv = sparse.diags(1 / mu_parts[2]) + mu_xy = sparse.diags_array(numpy.hstack((mu_parts[0], mu_parts[1]))) + mu_z_inv = sparse.diags_array(1 / mu_parts[2]) op = ( omega * omega * eps_yx @ mu_xy @@ -331,15 +329,15 @@ def operator_h( def normalized_fields_e( - e_xy: ArrayLike, + e_xy: vcfdfield2, wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, prop_phase: float = 0, - ) -> tuple[vcfdfield_t, vcfdfield_t]: - """ + ) -> tuple[vcfdslice_t, vcfdslice_t]: + r""" Given a vector `e_xy` containing the vectorized E_x and E_y fields, returns normalized, vectorized E and H fields for the system. @@ -357,24 +355,40 @@ def normalized_fields_e( Returns: `(e, h)`, where each field is vectorized, normalized, and contains all three vector components. + + Notes: + `e_xy` is only the transverse electric eigenvector. This helper first + reconstructs the full three-component `E` and `H` fields with `exy2e(...)` + and `exy2h(...)`, then normalizes them to unit forward power using + `_normalized_fields(...)`. + + The normalization target is + + $$ + \Re\left[\mathrm{inner\_product}(e, h, \mathrm{conj\_h}=True)\right] = 1, + $$ + + so the returned fields represent a unit-power forward mode under the + discrete Yee-grid Poynting inner product. """ e = exy2e(wavenumber=wavenumber, dxes=dxes, epsilon=epsilon) @ e_xy h = exy2h(wavenumber=wavenumber, omega=omega, dxes=dxes, epsilon=epsilon, mu=mu) @ e_xy - e_norm, h_norm = _normalized_fields(e=e, h=h, omega=omega, dxes=dxes, epsilon=epsilon, - mu=mu, prop_phase=prop_phase) + e_norm, h_norm = _normalized_fields( + e=e, h=h, dxes=dxes, epsilon=epsilon, prop_phase=prop_phase, + ) return e_norm, h_norm def normalized_fields_h( - h_xy: ArrayLike, + h_xy: vcfdfield2, wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, prop_phase: float = 0, - ) -> tuple[vcfdfield_t, vcfdfield_t]: - """ + ) -> tuple[vcfdslice_t, vcfdslice_t]: + r""" Given a vector `h_xy` containing the vectorized H_x and H_y fields, returns normalized, vectorized E and H fields for the system. @@ -392,39 +406,55 @@ def normalized_fields_h( Returns: `(e, h)`, where each field is vectorized, normalized, and contains all three vector components. + + Notes: + This is the `H_x/H_y` analogue of `normalized_fields_e(...)`. The final + normalized mode should describe the same physical solution, but because + the overall complex phase and sign are chosen heuristically, + `normalized_fields_e(...)` and `normalized_fields_h(...)` need not return + identical representatives for nearly symmetric modes. """ e = hxy2e(wavenumber=wavenumber, omega=omega, dxes=dxes, epsilon=epsilon, mu=mu) @ h_xy h = hxy2h(wavenumber=wavenumber, dxes=dxes, mu=mu) @ h_xy - e_norm, h_norm = _normalized_fields(e=e, h=h, omega=omega, dxes=dxes, epsilon=epsilon, - mu=mu, prop_phase=prop_phase) + e_norm, h_norm = _normalized_fields( + e=e, h=h, dxes=dxes, epsilon=epsilon, prop_phase=prop_phase, + ) return e_norm, h_norm def _normalized_fields( - e: vcfdfield_t, - h: vcfdfield_t, - omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, + e: vcfdslice, + h: vcfdslice, + dxes: dx_lists2_t, + epsilon: vfdslice, prop_phase: float = 0, - ) -> tuple[vcfdfield_t, vcfdfield_t]: - # TODO documentation - shape = [s.size for s in dxes[0]] - dxes_real = [[numpy.real(d) for d in numpy.meshgrid(*dxes[v], indexing='ij')] for v in (0, 1)] + ) -> tuple[vcfdslice_t, vcfdslice_t]: + r""" + Normalize a reconstructed waveguide mode to unit forward power. - E = unvec(e, shape) - H = unvec(h, shape) + The eigenproblem solved by `solve_mode(s)` determines only the mode shape and + propagation constant. The overall complex amplitude and sign are still free. + This helper fixes those remaining degrees of freedom in two steps: + + 1. Compute the discrete longitudinal Poynting flux with + `inner_product(e, h, conj_h=True)`, including the half-cell longitudinal + phase adjustment controlled by `prop_phase`. + 2. Multiply both fields by a scalar chosen so that the real forward power is + `1`, then choose a reproducible phase/sign representative by making a + dominant-energy sample real and using a weighted quadrant sum to break + mirror-symmetry ties. + + The sign heuristic is intentionally pragmatic rather than fundamental: it is + only there to make downstream tests and source/overlap construction choose a + consistent representative when the physical mode is symmetric. + """ + shape = [s.size for s in dxes[0]] # Find time-averaged Sz and normalize to it - # H phase is adjusted by a half-cell forward shift for Yee cell, and 1-cell reverse shift for Poynting - phase = numpy.exp(-1j * -prop_phase / 2) - Sz_a = E[0] * numpy.conj(H[1] * phase) * dxes_real[0][1] * dxes_real[1][0] - Sz_b = E[1] * numpy.conj(H[0] * phase) * dxes_real[0][0] * dxes_real[1][1] - Sz_tavg = numpy.real(Sz_a.sum() - Sz_b.sum()) * 0.5 # 0.5 since E, H are assumed to be peak (not RMS) amplitudes + Sz_tavg = inner_product(e, h, dxes=dxes, prop_phase=prop_phase, conj_h=True).real assert Sz_tavg > 0, f'Found a mode propagating in the wrong direction! {Sz_tavg=}' - energy = epsilon * e.conj() * e + energy = numpy.real(epsilon * e.conj() * e) norm_amplitude = 1 / numpy.sqrt(Sz_tavg) norm_angle = -numpy.angle(e[energy.argmax()]) # Will randomly add a negative sign when mode is symmetric @@ -434,22 +464,23 @@ def _normalized_fields( sign = numpy.sign(E_weighted[:, :max(shape[0] // 2, 1), :max(shape[1] // 2, 1)].real.sum()) + assert sign != 0 norm_factor = sign * norm_amplitude * numpy.exp(1j * norm_angle) e *= norm_factor h *= norm_factor - return e, h + return vcfdslice_t(e), vcfdslice_t(h) def exy2h( wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None + ) -> sparse.sparray: """ Operator which transforms the vector `e_xy` containing the vectorized E_x and E_y fields, into a vectorized H containing all three H components @@ -472,10 +503,10 @@ def exy2h( def hxy2e( wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None + ) -> sparse.sparray: """ Operator which transforms the vector `h_xy` containing the vectorized H_x and H_y fields, into a vectorized E containing all three E components @@ -497,9 +528,9 @@ def hxy2e( def hxy2h( wavenumber: complex, - dxes: dx_lists_t, - mu: vfdfield_t | None = None - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + mu: vfdslice | None = None + ) -> sparse.sparray: """ Operator which transforms the vector `h_xy` containing the vectorized H_x and H_y fields, into a vectorized H containing all three H components @@ -518,26 +549,53 @@ def hxy2h( if mu is not None: mu_parts = numpy.split(mu, 3) - mu_xy = sparse.diags(numpy.hstack((mu_parts[0], mu_parts[1]))) - mu_z_inv = sparse.diags(1 / mu_parts[2]) + mu_xy = sparse.diags_array(numpy.hstack((mu_parts[0], mu_parts[1]))) + mu_z_inv = sparse.diags_array(1 / mu_parts[2]) hxy2hz = mu_z_inv @ hxy2hz @ mu_xy n_pts = dxes[1][0].size * dxes[1][1].size - op = sparse.vstack((sparse.eye(2 * n_pts), + op = sparse.vstack((sparse.eye_array(2 * n_pts), hxy2hz)) return op def exy2e( wavenumber: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - ) -> sparse.spmatrix: - """ + dxes: dx_lists2_t, + epsilon: vfdslice, + ) -> sparse.sparray: + r""" Operator which transforms the vector `e_xy` containing the vectorized E_x and E_y fields, into a vectorized E containing all three E components + From the operator derivation (see module docs), we have + + $$ + \imath \omega \epsilon_{zz} E_z = \hat{\partial}_x H_y - \hat{\partial}_y H_x \\ + $$ + + as well as the intermediate equations + + $$ + \begin{aligned} + \imath \beta H_y &= \imath \omega \epsilon_{xx} E_x - \hat{\partial}_y H_z \\ + \imath \beta H_x &= -\imath \omega \epsilon_{yy} E_y - \hat{\partial}_x H_z \\ + \end{aligned} + $$ + + Combining these, we get + + $$ + \begin{aligned} + E_z &= \frac{1}{- \omega \beta \epsilon_{zz}} (( + \hat{\partial}_y \hat{\partial}_x H_z + -\hat{\partial}_x \hat{\partial}_y H_z) + + \imath \omega (\hat{\partial}_x \epsilon_{xx} E_x + \hat{\partial}_y \epsilon{yy} E_y)) + &= \frac{1}{\imath \beta \epsilon_{zz}} (\hat{\partial}_x \epsilon_{xx} E_x + \hat{\partial}_y \epsilon{yy} E_y) + \end{aligned} + $$ + Args: wavenumber: Wavenumber assuming fields have z-dependence of `exp(-i * wavenumber * z)` It should satisfy `operator_e() @ e_xy == wavenumber**2 * e_xy` @@ -552,13 +610,13 @@ def exy2e( if epsilon is not None: epsilon_parts = numpy.split(epsilon, 3) - epsilon_xy = sparse.diags(numpy.hstack((epsilon_parts[0], epsilon_parts[1]))) - epsilon_z_inv = sparse.diags(1 / epsilon_parts[2]) + epsilon_xy = sparse.diags_array(numpy.hstack((epsilon_parts[0], epsilon_parts[1]))) + epsilon_z_inv = sparse.diags_array(1 / epsilon_parts[2]) exy2ez = epsilon_z_inv @ exy2ez @ epsilon_xy n_pts = dxes[0][0].size * dxes[0][1].size - op = sparse.vstack((sparse.eye(2 * n_pts), + op = sparse.vstack((sparse.eye_array(2 * n_pts), exy2ez)) return op @@ -566,12 +624,12 @@ def exy2e( def e2h( wavenumber: complex, omega: complex, - dxes: dx_lists_t, - mu: vfdfield_t | None = None - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + mu: vfdslice | None = None + ) -> sparse.sparray: """ Returns an operator which, when applied to a vectorized E eigenfield, produces - the vectorized H eigenfield. + the vectorized H eigenfield slice. Args: wavenumber: Wavenumber assuming fields have z-dependence of `exp(-i * wavenumber * z)` @@ -584,19 +642,19 @@ def e2h( """ op = curl_e(wavenumber, dxes) / (-1j * omega) if mu is not None: - op = sparse.diags(1 / mu) @ op + op = sparse.diags_array(1 / mu) @ op return op def h2e( wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t - ) -> sparse.spmatrix: + dxes: dx_lists2_t, + epsilon: vfdslice, + ) -> sparse.sparray: """ Returns an operator which, when applied to a vectorized H eigenfield, produces - the vectorized E eigenfield. + the vectorized E eigenfield slice. Args: wavenumber: Wavenumber assuming fields have z-dependence of `exp(-i * wavenumber * z)` @@ -607,13 +665,13 @@ def h2e( Returns: Sparse matrix representation of the operator. """ - op = sparse.diags(1 / (1j * omega * epsilon)) @ curl_h(wavenumber, dxes) + op = sparse.diags_array(1 / (1j * omega * epsilon)) @ curl_h(wavenumber, dxes) return op -def curl_e(wavenumber: complex, dxes: dx_lists_t) -> sparse.spmatrix: +def curl_e(wavenumber: complex, dxes: dx_lists2_t) -> sparse.sparray: """ - Discretized curl operator for use with the waveguide E field. + Discretized curl operator for use with the waveguide E field slice. Args: wavenumber: Wavenumber assuming fields have z-dependence of `exp(-i * wavenumber * z)` @@ -622,18 +680,18 @@ def curl_e(wavenumber: complex, dxes: dx_lists_t) -> sparse.spmatrix: Returns: Sparse matrix representation of the operator. """ - n = 1 - for d in dxes[0]: - n *= len(d) + nn = 1 + for dd in dxes[0]: + nn *= len(dd) - Bz = -1j * wavenumber * sparse.eye(n) + Bz = -1j * wavenumber * sparse.eye_array(nn) Dfx, Dfy = deriv_forward(dxes[0]) return cross([Dfx, Dfy, Bz]) -def curl_h(wavenumber: complex, dxes: dx_lists_t) -> sparse.spmatrix: +def curl_h(wavenumber: complex, dxes: dx_lists2_t) -> sparse.sparray: """ - Discretized curl operator for use with the waveguide H field. + Discretized curl operator for use with the waveguide H field slice. Args: wavenumber: Wavenumber assuming fields have z-dependence of `exp(-i * wavenumber * z)` @@ -642,22 +700,22 @@ def curl_h(wavenumber: complex, dxes: dx_lists_t) -> sparse.spmatrix: Returns: Sparse matrix representation of the operator. """ - n = 1 - for d in dxes[1]: - n *= len(d) + nn = 1 + for dd in dxes[1]: + nn *= len(dd) - Bz = -1j * wavenumber * sparse.eye(n) + Bz = -1j * wavenumber * sparse.eye_array(nn) Dbx, Dby = deriv_back(dxes[1]) return cross([Dbx, Dby, Bz]) def h_err( - h: vcfdfield_t, + h: vcfdslice, wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None ) -> float: """ Calculates the relative error in the H field @@ -676,7 +734,7 @@ def h_err( ce = curl_e(wavenumber, dxes) ch = curl_h(wavenumber, dxes) - eps_inv = sparse.diags(1 / epsilon) + eps_inv = sparse.diags_array(1 / epsilon) if mu is None: op = ce @ eps_inv @ ch @ h - omega ** 2 * h @@ -687,12 +745,12 @@ def h_err( def e_err( - e: vcfdfield_t, + e: vcfdslice, wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, ) -> float: """ Calculates the relative error in the E field @@ -714,21 +772,21 @@ def e_err( if mu is None: op = ch @ ce @ e - omega ** 2 * (epsilon * e) else: - mu_inv = sparse.diags(1 / mu) + mu_inv = sparse.diags_array(1 / mu) op = ch @ mu_inv @ ce @ e - omega ** 2 * (epsilon * e) return float(norm(op) / norm(e)) def sensitivity( - e_norm: vcfdfield_t, - h_norm: vcfdfield_t, + e_norm: vcfdslice, + h_norm: vcfdslice, wavenumber: complex, omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, - ) -> vcfdfield_t: + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, + ) -> vcfdslice_t: r""" Given a waveguide structure (`dxes`, `epsilon`, `mu`) and mode fields (`e_norm`, `h_norm`, `wavenumber`, `omega`), calculates the sensitivity of the wavenumber @@ -802,11 +860,11 @@ def sensitivity( Dbx, Dby = deriv_back(dxes[1]) eps_x, eps_y, eps_z = numpy.split(epsilon, 3) - eps_xy = sparse.diags(numpy.hstack((eps_x, eps_y))) - eps_z_inv = sparse.diags(1 / eps_z) + eps_xy = sparse.diags_array(numpy.hstack((eps_x, eps_y))) + eps_z_inv = sparse.diags_array(1 / eps_z) mu_x, mu_y, _mu_z = numpy.split(mu, 3) - mu_yx = sparse.diags(numpy.hstack((mu_y, mu_x))) + mu_yx = sparse.diags_array(numpy.hstack((mu_y, mu_x))) da_exxhyy = vec(dxes[1][0][:, None] * dxes[0][1][None, :]) da_eyyhxx = vec(dxes[1][1][None, :] * dxes[0][0][:, None]) @@ -820,15 +878,15 @@ def sensitivity( norm = hv_yx_conj @ ev_xy sens_tot = numpy.concatenate([sens_xy1 + sens_xy2, sens_z]) / (2 * wavenumber * norm) - return sens_tot + return vcfdslice_t(sens_tot) def solve_modes( - mode_numbers: list[int], + mode_numbers: Sequence[int], omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - mu: vfdfield_t | None = None, + dxes: dx_lists2_t, + epsilon: vfdslice, + mu: vfdslice | None = None, mode_margin: int = 2, ) -> tuple[NDArray[numpy.complex128], NDArray[numpy.complex128]]: """ @@ -845,32 +903,38 @@ def solve_modes( ability to find the correct mode. Default 2. Returns: - e_xys: list of vfdfield_t specifying fields + e_xys: NDArray of vfdfield_t specifying fields. First dimension is mode number. wavenumbers: list of wavenumbers """ - ''' - Solve for the largest-magnitude eigenvalue of the real operator - ''' + # + # Solve for the largest-magnitude eigenvalue of the real operator + # dxes_real = [[numpy.real(dx) for dx in dxi] for dxi in dxes] mu_real = None if mu is None else numpy.real(mu) A_r = operator_e(numpy.real(omega), dxes_real, numpy.real(epsilon), mu_real) eigvals, eigvecs = signed_eigensolve(A_r, max(mode_numbers) + mode_margin) - e_xys = eigvecs[:, -(numpy.array(mode_numbers) + 1)] + keep_inds = -(numpy.array(mode_numbers) + 1) + e_xys = eigvecs[:, keep_inds].T + eigvals = eigvals[keep_inds] - ''' - Now solve for the eigenvector of the full operator, using the real operator's - eigenvector as an initial guess for Rayleigh quotient iteration. - ''' + # + # Now solve for the eigenvector of the full operator, using the real operator's + # eigenvector as an initial guess for Rayleigh quotient iteration. + # A = operator_e(omega, dxes, epsilon, mu) for nn in range(len(mode_numbers)): - eigvals[nn], e_xys[:, nn] = rayleigh_quotient_iteration(A, e_xys[:, nn]) + eigvals[nn], e_xys[nn, :] = rayleigh_quotient_iteration(A, e_xys[nn, :]) # Calculate the wave-vector (force the real part to be positive) wavenumbers = numpy.sqrt(eigvals) wavenumbers *= numpy.sign(numpy.real(wavenumbers)) + order = wavenumbers.argsort()[::-1] + e_xys = e_xys[order] + wavenumbers = wavenumbers[order] + return e_xys, wavenumbers @@ -878,7 +942,7 @@ def solve_mode( mode_number: int, *args: Any, **kwargs: Any, - ) -> tuple[vcfdfield_t, complex]: + ) -> tuple[vcfdfield2_t, complex]: """ Wrapper around `solve_modes()` that solves for a single mode. @@ -892,4 +956,66 @@ def solve_mode( """ kwargs['mode_numbers'] = [mode_number] e_xys, wavenumbers = solve_modes(*args, **kwargs) - return e_xys[:, 0], wavenumbers[0] + return vcfdfield2_t(e_xys[0]), wavenumbers[0] + + +def inner_product( + e1: vcfdfield2, + h2: vcfdfield2, + dxes: dx_lists2_t, + prop_phase: float = 0, + conj_h: bool = False, + trapezoid: bool = False, + ) -> complex: + r""" + Compute the discrete waveguide overlap / Poynting inner product. + + This is the 2D transverse integral corresponding to the time-averaged + longitudinal Poynting flux, + + $$ + \frac{1}{2}\int (E_x H_y - E_y H_x) \, dx \, dy + $$ + + with the Yee-grid staggering and optional propagation-phase adjustment used + by the waveguide helpers in this module. + + Args: + e1: Vectorized electric field, typically from `exy2e(...)` or + `normalized_fields_e(...)`. + h2: Vectorized magnetic field, typically from `hxy2h(...)`, + `exy2h(...)`, or one of the normalization helpers. + dxes: Two-dimensional Yee-grid spacing lists `[dx_e, dx_h]`. + prop_phase: Phase advance over one propagation cell. This is used to + shift the H field into the same longitudinal reference plane as the + E field. + conj_h: Whether to conjugate `h2` before forming the overlap. Use + `True` for the usual time-averaged power normalization. + trapezoid: Whether to use trapezoidal quadrature instead of the default + rectangular Yee-cell sum. + + Returns: + Complex overlap / longitudinal power integral. + """ + + shape = [s.size for s in dxes[0]] + + # H phase is adjusted by a half-cell forward shift for Yee cell, and 1-cell reverse shift for Poynting + phase = numpy.exp(-1j * -prop_phase / 2) + + E1 = unvec(e1, shape) + H2 = unvec(h2, shape) * phase + + if conj_h: + H2 = numpy.conj(H2) + + # Find time-averaged Sz and normalize to it + dxes_real = [[numpy.real(dxyz) for dxyz in dxeh] for dxeh in dxes] + if trapezoid: + Sz_a = numpy.trapezoid(numpy.trapezoid(E1[0] * H2[1], numpy.cumsum(dxes_real[0][1])), numpy.cumsum(dxes_real[1][0])) + Sz_b = numpy.trapezoid(numpy.trapezoid(E1[1] * H2[0], numpy.cumsum(dxes_real[0][0])), numpy.cumsum(dxes_real[1][1])) + else: + Sz_a = E1[0] * H2[1] * dxes_real[1][0][:, None] * dxes_real[0][1][None, :] + Sz_b = E1[1] * H2[0] * dxes_real[0][0][:, None] * dxes_real[1][1][None, :] + Sz = 0.5 * (Sz_a.sum() - Sz_b.sum()) + return Sz diff --git a/meanas/fdfd/waveguide_3d.py b/meanas/fdfd/waveguide_3d.py index 7f994d3..c77c8d4 100644 --- a/meanas/fdfd/waveguide_3d.py +++ b/meanas/fdfd/waveguide_3d.py @@ -3,15 +3,40 @@ Tools for working with waveguide modes in 3D domains. This module relies heavily on `waveguide_2d` and mostly just transforms its parameters into 2D equivalents and expands the results back into 3D. + +The intended workflow is: + +1. Select a single-cell slice normal to the propagation axis. +2. Solve the corresponding 2D mode problem with `solve_mode(...)`. +3. Turn that mode into a one-sided source with `compute_source(...)`. +4. Build an overlap window with `compute_overlap_e(...)` for port readout. + +`polarity` is part of the public convention throughout this module: + +- `+1` means forward propagation toward increasing index along `axis` +- `-1` means backward propagation toward decreasing index along `axis` + +That same convention controls which side of the selected slice is used for the +overlap window and how the expanded field is phased. """ -from typing import Sequence, Any +from typing import Any, TypedDict, cast +import warnings +from collections.abc import Sequence import numpy from numpy.typing import NDArray +from numpy import complexfloating -from ..fdmath import vec, unvec, dx_lists_t, fdfield_t, cfdfield_t +from ..fdmath import vec, unvec, dx_lists_t, cfdfield_t, fdfield, cfdfield from . import operators, waveguide_2d +class Waveguide3DMode(TypedDict): + wavenumber: complex + wavenumber_2d: complex + H: NDArray[complexfloating] + E: NDArray[complexfloating] + + def solve_mode( mode_number: int, omega: complex, @@ -19,12 +44,12 @@ def solve_mode( axis: int, polarity: int, slices: Sequence[slice], - epsilon: fdfield_t, - mu: fdfield_t | None = None, - ) -> dict[str, complex | NDArray[numpy.float_]]: - """ + epsilon: fdfield, + mu: fdfield | None = None, + ) -> Waveguide3DMode: + r""" Given a 3D grid, selects a slice from the grid and attempts to - solve for an eigenmode propagating through that slice. + solve for an eigenmode propagating through that slice. Args: mode_number: Number of the mode, 0-indexed @@ -33,27 +58,31 @@ def solve_mode( axis: Propagation axis (0=x, 1=y, 2=z) polarity: Propagation direction (+1 for +ve, -1 for -ve) slices: `epsilon[tuple(slices)]` is used to select the portion of the grid to use - as the waveguide cross-section. `slices[axis]` should select only one item. + as the waveguide cross-section. `slices[axis]` must select exactly one item. epsilon: Dielectric constant mu: Magnetic permeability (default 1 everywhere) Returns: - ``` - { - 'E': list[NDArray[numpy.float_]], - 'H': list[NDArray[numpy.float_]], - 'wavenumber': complex, - } - ``` + Dictionary containing: + + - `E`: full-grid electric field for the solved mode + - `H`: full-grid magnetic field for the solved mode + - `wavenumber`: propagation constant corrected for the discretized + propagation axis + - `wavenumber_2d`: propagation constant of the reduced 2D eigenproblem + + Notes: + The returned fields are normalized through the `waveguide_2d` + normalization convention before being expanded back to 3D. """ if mu is None: mu = numpy.ones_like(epsilon) slices = tuple(slices) - ''' - Solve the 2D problem in the specified plane - ''' + # + # Solve the 2D problem in the specified plane + # # Define rotation to set z as propagation direction order = numpy.roll(range(3), 2 - axis) reverse_order = numpy.roll(range(3), axis - 2) @@ -71,9 +100,10 @@ def solve_mode( } e_xy, wavenumber_2d = waveguide_2d.solve_mode(mode_number, **args_2d) - ''' - Apply corrections and expand to 3D - ''' + # + # Apply corrections and expand to 3D + # + # Correct wavenumber to account for numerical dispersion. wavenumber = 2 / dx_prop * numpy.arcsin(wavenumber_2d * dx_prop / 2) @@ -92,11 +122,12 @@ def solve_mode( # Expand E, H to full epsilon space we were given E = numpy.zeros_like(epsilon, dtype=complex) H = numpy.zeros_like(epsilon, dtype=complex) - for a, o in enumerate(reverse_order): - E[(a, *slices)] = e[o][:, :, None].transpose(reverse_order) - H[(a, *slices)] = h[o][:, :, None].transpose(reverse_order) + for aa, oo in enumerate(reverse_order): + iii = cast('tuple[slice | int]', (aa, *slices)) + E[iii] = e[oo][:, :, None].transpose(reverse_order) + H[iii] = h[oo][:, :, None].transpose(reverse_order) - results = { + results: Waveguide3DMode = { 'wavenumber': wavenumber, 'wavenumber_2d': wavenumber_2d, 'H': H, @@ -106,15 +137,15 @@ def solve_mode( def compute_source( - E: cfdfield_t, + E: cfdfield, wavenumber: complex, omega: complex, dxes: dx_lists_t, axis: int, polarity: int, slices: Sequence[slice], - epsilon: fdfield_t, - mu: fdfield_t | None = None, + epsilon: fdfield, + mu: fdfield | None = None, ) -> cfdfield_t: """ Given an eigenmode obtained by `solve_mode`, returns the current source distribution @@ -132,7 +163,14 @@ def compute_source( mu: Magnetic permeability (default 1 everywhere) Returns: - J distribution for the unidirectional source + `J` distribution for a one-sided electric-current source. + + Notes: + The source is built from the expanded mode field and a boundary-source + operator. The resulting current is intended to be injected with the + same sign convention used elsewhere in the package: + + `E -= dt * J / epsilon` """ E_expanded = expand_e(E=E, dxes=dxes, wavenumber=wavenumber, axis=axis, polarity=polarity, slices=slices) @@ -148,66 +186,113 @@ def compute_source( masked_e2j = operators.e_boundary_source(mask=vec(mask), omega=omega, dxes=dxes, epsilon=vec(epsilon), mu=vec(mu)) J = unvec(masked_e2j @ vec(E_expanded), E.shape[1:]) - return J + return cfdfield_t(J) def compute_overlap_e( - E: cfdfield_t, - wavenumber: complex, - dxes: dx_lists_t, - axis: int, - polarity: int, - slices: Sequence[slice], - ) -> cfdfield_t: # TODO DOCS - """ - Given an eigenmode obtained by `solve_mode`, calculates an overlap_e for the - mode orthogonality relation Integrate(((E x H_mode) + (E_mode x H)) dot dn) - [assumes reflection symmetry]. - - TODO: add reference - - Args: - E: E-field of the mode - H: H-field of the mode (advanced by half of a Yee cell from E) - wavenumber: Wavenumber of the mode - omega: Angular frequency of the simulation - dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` - axis: Propagation axis (0=x, 1=y, 2=z) - polarity: Propagation direction (+1 for +ve, -1 for -ve) - slices: `epsilon[tuple(slices)]` is used to select the portion of the grid to use - as the waveguide cross-section. slices[axis] should select only one item. - mu: Magnetic permeability (default 1 everywhere) - - Returns: - overlap_e such that `numpy.sum(overlap_e * other_e.conj())` computes the overlap integral - """ - slices = tuple(slices) - - Ee = expand_e(E=E, wavenumber=wavenumber, dxes=dxes, - axis=axis, polarity=polarity, slices=slices) - - start, stop = sorted((slices[axis].start, slices[axis].start - 2 * polarity)) - - slices2_l = list(slices) - slices2_l[axis] = slice(start, stop) - slices2 = (slice(None), *slices2_l) - - Etgt = numpy.zeros_like(Ee) - Etgt[slices2] = Ee[slices2] - - Etgt /= (Etgt.conj() * Etgt).sum() - return Etgt - - -def expand_e( - E: cfdfield_t, + E: cfdfield, wavenumber: complex, dxes: dx_lists_t, axis: int, polarity: int, slices: Sequence[slice], ) -> cfdfield_t: + r""" + Build an overlap field for projecting another 3D electric field onto a mode. + + The returned field is intended for the discrete overlap expression + + $$ + \sum \mathrm{overlap\_e} \; E_\mathrm{other}^* + $$ + + where the sum is over the full Yee-grid field storage. + + The construction uses a two-cell window immediately upstream of the selected + slice: + + - for `polarity=+1`, the two cells just before `slices[axis].start` + - for `polarity=-1`, the two cells just after `slices[axis].stop` + + The window is clipped to the simulation domain if necessary. A clipped but + non-empty window raises `RuntimeWarning`; an empty window raises + `ValueError`. + + The derivation below assumes reflection symmetry and the standard waveguide + overlap relation involving + + $$ + \int ((E \times H_\mathrm{mode}) + (E_\mathrm{mode} \times H)) \cdot dn. + $$ + + E x H_mode + E_mode x H + -> Ex Hmy - EyHmx + Emx Hy - Emy Hx (Z-prop) + Ex we/B Emx + Ex i/B dy Hmz - Ey (-we/B Emy) - Ey i/B dx Hmz + we/B (Ex Emx + Ey Emy) + i/B (Ex dy Hmz - Ey dx Hmz) + we/B (Ex Emx + Ey Emy) + i/B (Ex dy (dx Emy - dy Emx) - Ey dx (dx Emy - dy Emx)) + we/B (Ex Emx + Ey Emy) + i/B (Ex dy dx Emy - Ex dy dy Emx - Ey dx dx Emy - Ey dx dy Emx) + + Ex j/wu (-jB Emx - dx Emz) - Ey j/wu (dy Emz + jB Emy) + B/wu (Ex Emx + Ey Emy) - j/wu (Ex dx Emz + Ey dy Emz) + + + Args: + E: E-field of the mode + wavenumber: Wavenumber of the mode + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` + axis: Propagation axis (0=x, 1=y, 2=z) + polarity: Propagation direction (+1 for +ve, -1 for -ve) + slices: `epsilon[tuple(slices)]` is used to select the portion of the grid to use + as the waveguide cross-section. slices[axis] should select only one item. + + Returns: + `overlap_e` normalized so that `numpy.sum(overlap_e * E.conj()) == 1` + over the retained overlap window. """ + slices = tuple(slices) + + Ee = expand_e(E=E, wavenumber=wavenumber, dxes=dxes, + axis=axis, polarity=polarity, slices=slices) + + axis_size = E.shape[axis + 1] + if polarity > 0: + start = slices[axis].start - 2 + stop = slices[axis].start + else: + start = slices[axis].stop + stop = slices[axis].stop + 2 + + clipped_start = max(0, start) + clipped_stop = min(axis_size, stop) + if clipped_start >= clipped_stop: + raise ValueError('Requested overlap window lies outside the domain') + if clipped_start != start or clipped_stop != stop: + warnings.warn('Requested overlap window was clipped to fit within the domain', RuntimeWarning, stacklevel=2) + + slices2_l = list(slices) + slices2_l[axis] = slice(clipped_start, clipped_stop) + slices2 = (slice(None), *slices2_l) + + Etgt = numpy.zeros_like(Ee) + Etgt[slices2] = Ee[slices2] + + # Note: We normalize so that (Etgt @ E.conj()) == 1, so (Etgt @ Etgt.conj) != 1 + norm = (Etgt.conj() * Etgt).sum() + if norm == 0: + raise ValueError('Requested overlap window contains no overlap field support') + Etgt = Etgt / norm + return cfdfield_t(Etgt) + + +def expand_e( + E: cfdfield, + wavenumber: complex, + dxes: dx_lists_t, + axis: int, + polarity: int, + slices: Sequence[slice], + ) -> cfdfield_t: + r""" Given an eigenmode obtained by `solve_mode`, expands the E-field from the 2D slice where the mode was calculated to the entire domain (along the propagation axis). This assumes the epsilon cross-section remains constant throughout the @@ -225,6 +310,16 @@ def expand_e( Returns: `E`, with the original field expanded along the specified `axis`. + + Notes: + This helper assumes that the waveguide cross-section remains constant + along the propagation axis and applies the phase factor + + $$ + e^{-i \, \mathrm{polarity} \, wavenumber \, \Delta z} + $$ + + to each copied slice. """ slices = tuple(slices) @@ -245,4 +340,4 @@ def expand_e( slices_in = (slice(None), *slices) E_expanded[slices_exp] = phase_E * numpy.array(E)[slices_in] - return E_expanded + return cfdfield_t(E_expanded) diff --git a/meanas/fdfd/waveguide_cyl.py b/meanas/fdfd/waveguide_cyl.py index d476caa..f2cb5c3 100644 --- a/meanas/fdfd/waveguide_cyl.py +++ b/meanas/fdfd/waveguide_cyl.py @@ -1,49 +1,181 @@ -""" +r""" Operators and helper functions for cylindrical waveguides with unchanging cross-section. -WORK IN PROGRESS, CURRENTLY BROKEN +Waveguide operator is derived according to 10.1364/OL.33.001848. -As the z-dependence is known, all the functions in this file assume a 2D grid - (i.e. `dxes = [[[dr_e_0, dx_e_1, ...], [dy_e_0, ...]], [[dr_h_0, ...], [dy_h_0, ...]]]`). +As in `waveguide_2d`, the propagation dependence is separated from the +transverse solve. Here the propagation coordinate is the bend angle `\theta`, +and the fields are assumed to have the form + +$$ +\vec{E}(r, y, \theta), \vec{H}(r, y, \theta) \propto e^{-\imath m \theta}, +$$ + +where `m` is the angular wavenumber returned by `solve_mode(s)`. It is often +convenient to introduce the corresponding linear wavenumber + +$$ +\beta = \frac{m}{r_{\min}}, +$$ + +so that the cylindrical problem resembles the straight-waveguide problem with +additional metric factors. + +Those metric factors live on the staggered radial Yee grids. If the left edge of +the computational window is at `r = r_{\min}`, define the electric-grid and +magnetic-grid radial sample locations by + +$$ +\begin{aligned} +r_a(n) &= r_{\min} + \sum_{j \le n} \Delta r_{e, j}, \\ +r_b\!\left(n + \tfrac{1}{2}\right) &= r_{\min} + \tfrac{1}{2}\Delta r_{e, n} + + \sum_{j < n} \Delta r_{h, j}, +\end{aligned} +$$ + +and from them the diagonal metric matrices + +$$ +\begin{aligned} +T_a &= \operatorname{diag}(r_a / r_{\min}), \\ +T_b &= \operatorname{diag}(r_b / r_{\min}). +\end{aligned} +$$ + +With the same forward/backward derivative notation used in `waveguide_2d`, the +coordinate-transformed discrete curl equations used here are + +$$ +\begin{aligned} +-\imath \omega \mu_{rr} H_r &= \tilde{\partial}_y E_z + \imath \beta T_a^{-1} E_y, \\ +-\imath \omega \mu_{yy} H_y &= -\imath \beta T_b^{-1} E_r + - T_b^{-1} \tilde{\partial}_r (T_a E_z), \\ +-\imath \omega \mu_{zz} H_z &= \tilde{\partial}_r E_y - \tilde{\partial}_y E_r, \\ +\imath \beta H_y &= -\imath \omega T_b \epsilon_{rr} E_r - T_b \hat{\partial}_y H_z, \\ +\imath \beta H_r &= \imath \omega T_a \epsilon_{yy} E_y + - T_b T_a^{-1} \hat{\partial}_r (T_b H_z), \\ +\imath \omega E_z &= T_a \epsilon_{zz}^{-1} + \left(\hat{\partial}_r H_y - \hat{\partial}_y H_r\right). +\end{aligned} +$$ + +The first three equations are the cylindrical analogue of the straight-guide +relations for `H_r`, `H_y`, and `H_z`. The next two are the metric-weighted +versions of the straight-guide identities for `\imath \beta H_y` and +`\imath \beta H_r`, and the last equation plays the same role as the +longitudinal `E_z` reconstruction in `waveguide_2d`. + +Following the same elimination steps as in `waveguide_2d`, apply +`\imath \beta \tilde{\partial}_r` and `\imath \beta \tilde{\partial}_y` to the +equation for `E_z`, substitute for `\imath \beta H_r` and `\imath \beta H_y`, +and then eliminate `H_z` with + +$$ +H_z = \frac{1}{-\imath \omega \mu_{zz}} +\left(\tilde{\partial}_r E_y - \tilde{\partial}_y E_r\right). +$$ + +This yields the transverse electric eigenproblem implemented by +`cylindrical_operator(...)`: + +$$ +\beta^2 +\begin{bmatrix} E_r \\ E_y \end{bmatrix} += +\left( +\omega^2 +\begin{bmatrix} +T_b^2 \mu_{yy} \epsilon_{xx} & 0 \\ +0 & T_a^2 \mu_{xx} \epsilon_{yy} +\end{bmatrix} ++ +\begin{bmatrix} +-T_b \mu_{yy} \hat{\partial}_y \\ + T_a \mu_{xx} \hat{\partial}_x +\end{bmatrix} +T_b \mu_{zz}^{-1} +\begin{bmatrix} +-\tilde{\partial}_y & \tilde{\partial}_x +\end{bmatrix} ++ +\begin{bmatrix} +\tilde{\partial}_x \\ +\tilde{\partial}_y +\end{bmatrix} +T_a \epsilon_{zz}^{-1} +\begin{bmatrix} +\hat{\partial}_x T_b \epsilon_{xx} & +\hat{\partial}_y T_a \epsilon_{yy} +\end{bmatrix} +\right) +\begin{bmatrix} E_r \\ E_y \end{bmatrix}. +$$ + +Since `\beta = m / r_{\min}`, the solver implemented in this file returns the +angular wavenumber `m`, while the operator itself is most naturally written in +terms of the linear quantity `\beta`. The helpers below reconstruct the full +field components from the solved transverse eigenvector and then normalize the +mode to unit forward power with the same discrete longitudinal Poynting inner +product used by `waveguide_2d`. + +As in the straight-waveguide case, all functions here assume a 2D grid: + +`dxes = [[[dr_e_0, dr_e_1, ...], [dy_e_0, ...]], [[dr_h_0, ...], [dy_h_0, ...]]]`. """ -# TODO update module docs +from typing import Any, cast +from collections.abc import Sequence +import logging import numpy -import scipy.sparse as sparse # type: ignore +from numpy.typing import NDArray, ArrayLike +from scipy import sparse -from ..fdmath import vec, unvec, dx_lists_t, fdfield_t, vfdfield_t, cfdfield_t +from ..fdmath import vec, unvec, dx_lists2_t, vcfdslice_t, vfdslice, vcfdslice, vcfdfield2 from ..fdmath.operators import deriv_forward, deriv_back from ..eigensolvers import signed_eigensolve, rayleigh_quotient_iteration +from . import waveguide_2d + +logger = logging.getLogger(__name__) def cylindrical_operator( - omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - r0: float, - ) -> sparse.spmatrix: - """ + omega: float, + dxes: dx_lists2_t, + epsilon: vfdslice, + rmin: float, + ) -> sparse.sparray: + r""" Cylindrical coordinate waveguide operator of the form - (NOTE: See 10.1364/OL.33.001848) - TODO: consider 10.1364/OE.20.021583 - - TODO + $$ + (\omega^2 \begin{bmatrix} T_b T_b \mu_{yy} \epsilon_{xx} & 0 \\ + 0 & T_a T_a \mu_{xx} \epsilon_{yy} \end{bmatrix} + + \begin{bmatrix} -T_b \mu_{yy} \hat{\partial}_y \\ + T_a \mu_{xx} \hat{\partial}_x \end{bmatrix} T_b \mu_{zz}^{-1} + \begin{bmatrix} -\tilde{\partial}_y & \tilde{\partial}_x \end{bmatrix} + + \begin{bmatrix} \tilde{\partial}_x \\ + \tilde{\partial}_y \end{bmatrix} T_a \epsilon_{zz}^{-1} + \begin{bmatrix} \hat{\partial}_x T_b \epsilon_{xx} & \hat{\partial}_y T_a \epsilon_{yy} \end{bmatrix}) + \begin{bmatrix} E_r \\ + E_y \end{bmatrix} + $$ for use with a field vector of the form `[E_r, E_y]`. This operator can be used to form an eigenvalue problem of the form - A @ [E_r, E_y] = wavenumber**2 * [E_r, E_y] + A @ [E_r, E_y] = beta**2 * [E_r, E_y] which can then be solved for the eigenmodes of the system - (an `exp(-i * wavenumber * theta)` theta-dependence is assumed for the fields). + (an `exp(-i * angular_wavenumber * theta)` theta-dependence is assumed for + the fields, with `beta = angular_wavenumber / rmin`). + + (NOTE: See module docs and 10.1364/OL.33.001848) Args: omega: The angular frequency of the system dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) epsilon: Vectorized dielectric constant grid - r0: Radius of curvature for the simulation. This should be the minimum value of - r within the simulation domain. + rmin: Radius at the left edge of the simulation domain (at minimum 'x') Returns: Sparse matrix representation of the operator @@ -52,97 +184,409 @@ def cylindrical_operator( Dfx, Dfy = deriv_forward(dxes[0]) Dbx, Dby = deriv_back(dxes[1]) - rx = r0 + numpy.cumsum(dxes[0][0]) - ry = r0 + dxes[0][0] / 2.0 + numpy.cumsum(dxes[1][0]) - tx = rx / r0 - ty = ry / r0 - - Tx = sparse.diags(vec(tx[:, None].repeat(dxes[0][1].size, axis=1))) - Ty = sparse.diags(vec(ty[:, None].repeat(dxes[1][1].size, axis=1))) + Ta, Tb = dxes2T(dxes=dxes, rmin=rmin) eps_parts = numpy.split(epsilon, 3) - eps_x = sparse.diags(eps_parts[0]) - eps_y = sparse.diags(eps_parts[1]) - eps_z_inv = sparse.diags(1 / eps_parts[2]) - - pa = sparse.vstack((Dfx, Dfy)) @ Tx @ eps_z_inv @ sparse.hstack((Dbx, Dby)) - pb = sparse.vstack((Dfx, Dfy)) @ Tx @ eps_z_inv @ sparse.hstack((Dby, Dbx)) - a0 = Ty @ eps_x + omega**-2 * Dby @ Ty @ Dfy - a1 = Tx @ eps_y + omega**-2 * Dbx @ Ty @ Dfx - b0 = Dbx @ Ty @ Dfy - b1 = Dby @ Ty @ Dfx - - diag = sparse.block_diag + eps_x = sparse.diags_array(eps_parts[0]) + eps_y = sparse.diags_array(eps_parts[1]) + eps_z_inv = sparse.diags_array(1 / eps_parts[2]) omega2 = omega * omega + diag = sparse.block_diag - op = ( - (omega2 * diag((Tx, Ty)) + pa) @ diag((a0, a1)) - - (sparse.bmat(((None, Ty), (Tx, None))) + pb / omega2) @ diag((b0, b1)) - ) + sq0 = omega2 * diag((Tb @ Tb @ eps_x, + Ta @ Ta @ eps_y)) + lin0 = sparse.vstack((-Tb @ Dby, Ta @ Dbx)) @ Tb @ sparse.hstack((-Dfy, Dfx)) + lin1 = sparse.vstack((Dfx, Dfy)) @ Ta @ eps_z_inv @ sparse.hstack((Dbx @ Tb @ eps_x, + Dby @ Ta @ eps_y)) + op = sq0 + lin0 + lin1 return op -def solve_mode( - mode_number: int, - omega: complex, - dxes: dx_lists_t, - epsilon: vfdfield_t, - r0: float, - ) -> dict[str, complex | cfdfield_t]: +def solve_modes( + mode_numbers: Sequence[int], + omega: float, + dxes: dx_lists2_t, + epsilon: vfdslice, + rmin: float, + mode_margin: int = 2, + ) -> tuple[NDArray[numpy.complex128], NDArray[numpy.complex128]]: """ - TODO: fixup Given a 2d (r, y) slice of epsilon, attempts to solve for the eigenmode of the bent waveguide with the specified mode number. Args: - mode_number: Number of the mode, 0-indexed + mode_numbers: Mode numbers to solve, 0-indexed. omega: Angular frequency of the simulation dxes: Grid parameters [dx_e, dx_h] as described in meanas.fdmath.types. - The first coordinate is assumed to be r, the second is y. + The first coordinate is assumed to be r, the second is y. epsilon: Dielectric constant - r0: Radius of curvature for the simulation. This should be the minimum value of + rmin: Radius of curvature for the simulation. This should be the minimum value of r within the simulation domain. Returns: - ``` - { - 'E': list[NDArray[numpy.complex_]], - 'H': list[NDArray[numpy.complex_]], - 'wavenumber': complex, - } - ``` + e_xys: NDArray of vfdfield_t specifying fields. First dimension is mode number. + angular_wavenumbers: list of wavenumbers in 1/rad units. """ - ''' - Solve for the largest-magnitude eigenvalue of the real operator - ''' + # + # Solve for the largest-magnitude eigenvalue of the real operator + # dxes_real = [[numpy.real(dx) for dx in dxi] for dxi in dxes] - A_r = cylindrical_operator(numpy.real(omega), dxes_real, numpy.real(epsilon), r0) - eigvals, eigvecs = signed_eigensolve(A_r, mode_number + 3) - e_xy = eigvecs[:, -(mode_number + 1)] + A_r = cylindrical_operator(numpy.real(omega), dxes_real, numpy.real(epsilon), rmin=rmin) + eigvals, eigvecs = signed_eigensolve(A_r, max(mode_numbers) + mode_margin) + keep_inds = -(numpy.array(mode_numbers) + 1) + e_xys = eigvecs[:, keep_inds].T + eigvals = eigvals[keep_inds] - ''' - Now solve for the eigenvector of the full operator, using the real operator's - eigenvector as an initial guess for Rayleigh quotient iteration. - ''' - A = cylindrical_operator(omega, dxes, epsilon, r0) - eigval, e_xy = rayleigh_quotient_iteration(A, e_xy) + # + # Now solve for the eigenvector of the full operator, using the real operator's + # eigenvector as an initial guess for Rayleigh quotient iteration. + # + A = cylindrical_operator(omega, dxes, epsilon, rmin=rmin) + for nn in range(len(mode_numbers)): + eigvals[nn], e_xys[nn, :] = rayleigh_quotient_iteration(A, e_xys[nn, :]) # Calculate the wave-vector (force the real part to be positive) - wavenumber = numpy.sqrt(eigval) - wavenumber *= numpy.sign(numpy.real(wavenumber)) + wavenumbers = numpy.sqrt(eigvals) + wavenumbers *= numpy.sign(numpy.real(wavenumbers)) - # TODO: Perform correction on wavenumber to account for numerical dispersion. + # Wavenumbers assume the mode is at rmin, which is unlikely + # Instead, return the wavenumber in inverse radians + angular_wavenumbers = wavenumbers * cast('complex', rmin) - shape = [d.size for d in dxes[0]] - e_xy = numpy.hstack((e_xy, numpy.zeros(shape[0] * shape[1]))) - fields = { - 'wavenumber': wavenumber, - 'E': unvec(e_xy, shape), - # 'E': unvec(e, shape), - # 'H': unvec(h, shape), - } + order = angular_wavenumbers.argsort()[::-1] + e_xys = e_xys[order] + angular_wavenumbers = angular_wavenumbers[order] - return fields + return e_xys, angular_wavenumbers + + +def solve_mode( + mode_number: int, + *args: Any, + **kwargs: Any, + ) -> tuple[vcfdfield2, complex]: + """ + Wrapper around `solve_modes()` that solves for a single mode. + + Args: + mode_number: 0-indexed mode number to solve for + *args: passed to `solve_modes()` + **kwargs: passed to `solve_modes()` + + Returns: + (e_xy, angular_wavenumber) + """ + kwargs['mode_numbers'] = [mode_number] + e_xys, angular_wavenumbers = solve_modes(*args, **kwargs) + return e_xys[0], angular_wavenumbers[0] + + +def linear_wavenumbers( + e_xys: Sequence[vcfdfield2] | NDArray[numpy.complex128], + angular_wavenumbers: ArrayLike, + epsilon: vfdslice, + dxes: dx_lists2_t, + rmin: float, + ) -> NDArray[numpy.complex128]: + """ + Calculate linear wavenumbers (1/distance) based on angular wavenumbers (1/rad) + and the mode's energy distribution. + + Args: + e_xys: Vectorized mode fields with shape (num_modes, 2 * x *y) + angular_wavenumbers: Wavenumbers assuming fields have theta-dependence of + `exp(-i * angular_wavenumber * theta)`. They should satisfy + `operator_e() @ e_xy == (angular_wavenumber / rmin) ** 2 * e_xy` + epsilon: Vectorized dielectric constant grid with shape (3, x, y) + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) + rmin: Radius at the left edge of the simulation domain (at minimum 'x') + + Returns: + NDArray containing the calculated linear (1/distance) wavenumbers + """ + angular_wavenumbers = numpy.asarray(angular_wavenumbers) + mode_radii = numpy.empty_like(angular_wavenumbers, dtype=float) + + shape2d = (len(dxes[0][0]), len(dxes[0][1])) + epsilon2d = unvec(epsilon, shape2d)[:2] + grid_radii = rmin + numpy.cumsum(dxes[0][0]) + for ii in range(angular_wavenumbers.size): + efield = unvec(e_xys[ii], shape2d, 2) + energy = numpy.real((efield * efield.conj()) * epsilon2d) + energy_vs_x = energy.sum(axis=(0, 2)) + mode_radii[ii] = (grid_radii * energy_vs_x).sum() / energy_vs_x.sum() + + logger.info(f'{mode_radii=}') + lin_wavenumbers = angular_wavenumbers / mode_radii + return lin_wavenumbers + + +def exy2h( + angular_wavenumber: complex, + omega: float, + dxes: dx_lists2_t, + rmin: float, + epsilon: vfdslice, + mu: vfdslice | None = None + ) -> sparse.sparray: + """ + Operator which transforms the vector `e_xy` containing the vectorized E_r and E_y fields, + into a vectorized H containing all three H components + + Args: + angular_wavenumber: Wavenumber assuming fields have theta-dependence of + `exp(-i * angular_wavenumber * theta)`. It should satisfy + `operator_e() @ e_xy == (angular_wavenumber / rmin) ** 2 * e_xy` + omega: The angular frequency of the system + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) + rmin: Radius at the left edge of the simulation domain (at minimum 'x') + epsilon: Vectorized dielectric constant grid + mu: Vectorized magnetic permeability grid (default 1 everywhere) + + Returns: + Sparse matrix representing the operator. + """ + e2hop = e2h(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, mu=mu) + return e2hop @ exy2e(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon) + + +def exy2e( + angular_wavenumber: complex, + omega: float, + dxes: dx_lists2_t, + rmin: float, + epsilon: vfdslice, + ) -> sparse.sparray: + """ + Operator which transforms the vector `e_xy` containing the vectorized E_r and E_y fields, + into a vectorized E containing all three E components + + Unlike the straight waveguide case, the H_z components do not cancel and must be calculated + from E_r and E_y in order to then calculate E_z. + + Args: + angular_wavenumber: Wavenumber assuming fields have theta-dependence of + `exp(-i * angular_wavenumber * theta)`. It should satisfy + `operator_e() @ e_xy == (angular_wavenumber / rmin) ** 2 * e_xy` + omega: The angular frequency of the system + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) + rmin: Radius at the left edge of the simulation domain (at minimum 'x') + epsilon: Vectorized dielectric constant grid + + Returns: + Sparse matrix representing the operator. + """ + Dfx, Dfy = deriv_forward(dxes[0]) + Dbx, Dby = deriv_back(dxes[1]) + wavenumber = angular_wavenumber / rmin + + Ta, Tb = dxes2T(dxes=dxes, rmin=rmin) + Tai = sparse.diags_array(1 / Ta.diagonal()) + #Tbi = sparse.diags_array(1 / Tb.diagonal()) + + epsilon_parts = numpy.split(epsilon, 3) + epsilon_x, epsilon_y = (sparse.diags_array(epsi) for epsi in epsilon_parts[:2]) + epsilon_z_inv = sparse.diags_array(1 / epsilon_parts[2]) + + n_pts = dxes[0][0].size * dxes[0][1].size + zeros = sparse.coo_array((n_pts, n_pts)) + + mu_z = numpy.ones(n_pts) + mu_z_inv = sparse.diags_array(1 / mu_z) + exy2hz = 1 / (-1j * omega) * mu_z_inv @ sparse.hstack((Dfy, -Dfx)) + hxy2ez = 1 / (1j * omega) * epsilon_z_inv @ sparse.hstack((Dby, -Dbx)) + + exy2hy = Tb / (1j * wavenumber) @ (-1j * omega * sparse.hstack((epsilon_x, zeros)) - Dby @ exy2hz) + exy2hx = Tb / (1j * wavenumber) @ ( 1j * omega * sparse.hstack((zeros, epsilon_y)) - Tai @ Dbx @ Tb @ exy2hz) + + exy2ez = hxy2ez @ sparse.vstack((exy2hx, exy2hy)) + + op = sparse.vstack((sparse.eye_array(2 * n_pts), + exy2ez)) + return op + + +def e2h( + angular_wavenumber: complex, + omega: float, + dxes: dx_lists2_t, + rmin: float, + mu: vfdslice | None = None + ) -> sparse.sparray: + r""" + Returns an operator which, when applied to a vectorized E eigenfield, produces + the vectorized H eigenfield. + + This operator is created directly from the initial coordinate-transformed equations: + $$ + \begin{aligned} + -\imath \omega \mu_{rr} H_r &= \tilde{\partial}_y E_z + \imath \beta T_a^{-1} E_y, \\ + -\imath \omega \mu_{yy} H_y &= -\imath \beta T_b^{-1} E_r + - T_b^{-1} \tilde{\partial}_r (T_a E_z), \\ + -\imath \omega \mu_{zz} H_z &= \tilde{\partial}_r E_y - \tilde{\partial}_y E_r, + \end{aligned} + $$ + + Args: + angular_wavenumber: Wavenumber assuming fields have theta-dependence of + `exp(-i * angular_wavenumber * theta)`. It should satisfy + `operator_e() @ e_xy == (angular_wavenumber / rmin) ** 2 * e_xy` + omega: The angular frequency of the system + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) + rmin: Radius at the left edge of the simulation domain (at minimum 'x') + mu: Vectorized magnetic permeability grid (default 1 everywhere) + + Returns: + Sparse matrix representation of the operator. + """ + Dfx, Dfy = deriv_forward(dxes[0]) + Ta, Tb = dxes2T(dxes=dxes, rmin=rmin) + Tai = sparse.diags_array(1 / Ta.diagonal()) + Tbi = sparse.diags_array(1 / Tb.diagonal()) + + jB = 1j * angular_wavenumber / rmin + op = sparse.block_array([[ None, -jB * Tai, -Dfy], + [jB * Tbi, None, Tbi @ Dfx @ Ta], + [ Dfy, -Dfx, None]]) / (-1j * omega) + if mu is not None: + op = sparse.diags_array(1 / mu) @ op + return op + + +def dxes2T( + dxes: dx_lists2_t, + rmin: float, + ) -> tuple[NDArray[numpy.float64], NDArray[numpy.float64]]: + r""" + Construct the cylindrical metric matrices $T_a$ and $T_b$. + + `T_a` is sampled on the E-grid radial locations, while `T_b` is sampled on + the staggered H-grid radial locations. These are the diagonal matrices that + convert the straight-waveguide algebra into its cylindrical counterpart. + + Args: + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) + rmin: Radius at the left edge of the simulation domain (at minimum 'x') + + Returns: + Sparse diagonal matrices `(T_a, T_b)`. + """ + ra = rmin + numpy.cumsum(dxes[0][0]) # Radius at Ey points + rb = rmin + dxes[0][0] / 2.0 + numpy.cumsum(dxes[1][0]) # Radius at Ex points + ta = ra / rmin + tb = rb / rmin + + Ta = sparse.diags_array(vec(ta[:, None].repeat(dxes[0][1].size, axis=1))) + Tb = sparse.diags_array(vec(tb[:, None].repeat(dxes[1][1].size, axis=1))) + return Ta, Tb + + +def normalized_fields_e( + e_xy: vcfdfield2, + angular_wavenumber: complex, + omega: float, + dxes: dx_lists2_t, + rmin: float, + epsilon: vfdslice, + mu: vfdslice | None = None, + prop_phase: float = 0, + ) -> tuple[vcfdslice_t, vcfdslice_t]: + r""" + Given a vector `e_xy` containing the vectorized E_r and E_y fields, + returns normalized, vectorized E and H fields for the system. + + Args: + e_xy: Vector containing E_r and E_y fields + angular_wavenumber: Wavenumber assuming fields have theta-dependence of + `exp(-i * angular_wavenumber * theta)`. It should satisfy + `operator_e() @ e_xy == (angular_wavenumber / rmin) ** 2 * e_xy` + omega: The angular frequency of the system + dxes: Grid parameters `[dx_e, dx_h]` as described in `meanas.fdmath.types` (2D) + rmin: Radius at the left edge of the simulation domain (at minimum 'x') + epsilon: Vectorized dielectric constant grid + mu: Vectorized magnetic permeability grid (default 1 everywhere) + prop_phase: Phase shift `(dz * corrected_wavenumber)` over 1 cell in propagation direction. + Default 0 (continuous propagation direction, i.e. dz->0). + + Returns: + `(e, h)`, where each field is vectorized, normalized, + and contains all three vector components. + + Notes: + The normalization step is delegated to `_normalized_fields(...)`, which + enforces unit forward power under the discrete inner product + + $$ + \frac{1}{2}\int (E_r H_y^* - E_y H_r^*) \, dr \, dy. + $$ + + The angular wavenumber `m` is first converted into the full three-component + fields, then the overall complex phase and sign are fixed so the result is + reproducible for symmetric modes. + """ + e = exy2e(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon) @ e_xy + h = exy2h(angular_wavenumber=angular_wavenumber, omega=omega, dxes=dxes, rmin=rmin, epsilon=epsilon, mu=mu) @ e_xy + e_norm, h_norm = _normalized_fields( + e=e, h=h, dxes=dxes, epsilon=epsilon, prop_phase=prop_phase, + ) + return e_norm, h_norm + + +def _normalized_fields( + e: vcfdslice, + h: vcfdslice, + dxes: dx_lists2_t, + epsilon: vfdslice, + prop_phase: float = 0, + ) -> tuple[vcfdslice_t, vcfdslice_t]: + r""" + Normalize a cylindrical waveguide mode to unit forward power. + + The cylindrical helpers reuse the straight-waveguide inner product after the + field reconstruction step. The extra metric factors have already been folded + into the reconstructed `e`/`h` fields through `dxes2T(...)` and the + cylindrical `exy2e(...)` / `exy2h(...)` operators, so the same discrete + longitudinal Poynting integral can be used here. + + The normalization procedure is: + + 1. Flip the magnetic field sign so the reconstructed `(e, h)` pair follows + the same forward-power convention as `waveguide_2d`. + 2. Compute the time-averaged forward power with + `waveguide_2d.inner_product(..., conj_h=True)`. + 3. Scale by `1 / sqrt(S_z)` so the resulting mode has unit forward power. + 4. Remove the arbitrary complex phase and apply a quadrant-sum sign heuristic + so symmetric modes choose a stable representative. + + `prop_phase` has the same meaning as in `waveguide_2d`: it compensates for + the half-cell longitudinal staggering between the E and H fields when the + propagation direction is itself discretized. + """ + h *= -1 + shape = [s.size for s in dxes[0]] + + # Find time-averaged Sz and normalize to it + # H phase is adjusted by a half-cell forward shift for Yee cell, and 1-cell reverse shift for Poynting + Sz_tavg = waveguide_2d.inner_product(e, h, dxes=dxes, prop_phase=prop_phase, conj_h=True).real # Note, using linear poynting vector + assert Sz_tavg > 0, f'Found a mode propagating in the wrong direction! {Sz_tavg=}' + + energy = numpy.real(epsilon * e.conj() * e) + + norm_amplitude = 1 / numpy.sqrt(Sz_tavg) + norm_angle = -numpy.angle(e[energy.argmax()]) # Will randomly add a negative sign when mode is symmetric + + # Try to break symmetry to assign a consistent sign [experimental] + E_weighted = unvec(e * energy * numpy.exp(1j * norm_angle), shape) + sign = numpy.sign(E_weighted[:, + :max(shape[0] // 2, 1), + :max(shape[1] // 2, 1)].real.sum()) + assert sign != 0 + + norm_factor = sign * norm_amplitude * numpy.exp(1j * norm_angle) + + e *= norm_factor + h *= norm_factor + return vcfdslice_t(e), vcfdslice_t(h) diff --git a/meanas/fdmath/__init__.py b/meanas/fdmath/__init__.py index 8a6b784..857cf18 100644 --- a/meanas/fdmath/__init__.py +++ b/meanas/fdmath/__init__.py @@ -741,8 +741,46 @@ the true values can be multiplied back in after the simulation is complete if no normalized results are needed. """ -from .types import fdfield_t, vfdfield_t, cfdfield_t, vcfdfield_t, dx_lists_t, dx_lists_mut -from .types import fdfield_updater_t, cfdfield_updater_t -from .vectorization import vec, unvec -from . import operators, functional, types, vectorization +from .types import ( + fdfield_t as fdfield_t, + vfdfield_t as vfdfield_t, + cfdfield_t as cfdfield_t, + vcfdfield_t as vcfdfield_t, + fdfield2_t as fdfield2_t, + vfdfield2_t as vfdfield2_t, + cfdfield2_t as cfdfield2_t, + vcfdfield2_t as vcfdfield2_t, + fdfield as fdfield, + vfdfield as vfdfield, + cfdfield as cfdfield, + vcfdfield as vcfdfield, + fdfield2 as fdfield2, + vfdfield2 as vfdfield2, + cfdfield2 as cfdfield2, + vcfdfield2 as vcfdfield2, + fdslice_t as fdslice_t, + vfdslice_t as vfdslice_t, + cfdslice_t as cfdslice_t, + vcfdslice_t as vcfdslice_t, + fdslice as fdslice, + vfdslice as vfdslice, + cfdslice as cfdslice, + vcfdslice as vcfdslice, + dx_lists_t as dx_lists_t, + dx_lists2_t as dx_lists2_t, + dx_lists_mut as dx_lists_mut, + dx_lists2_mut as dx_lists2_mut, + fdfield_updater_t as fdfield_updater_t, + cfdfield_updater_t as cfdfield_updater_t, + ) +from .vectorization import ( + vec as vec, + unvec as unvec, + ) +from . import ( + operators as operators, + functional as functional, + types as types, + vectorization as vectorization, + ) diff --git a/meanas/fdmath/functional.py b/meanas/fdmath/functional.py index 3a10a00..27d368a 100644 --- a/meanas/fdmath/functional.py +++ b/meanas/fdmath/functional.py @@ -3,16 +3,18 @@ Math functions for finite difference simulations Basic discrete calculus etc. """ -from typing import Sequence, Callable +from typing import TypeVar +from collections.abc import Sequence, Callable import numpy from numpy.typing import NDArray +from numpy import floating, complexfloating -from .types import fdfield_t, fdfield_updater_t +from .types import fdfield, fdfield_updater_t def deriv_forward( - dx_e: Sequence[NDArray[numpy.float_]] | None = None, + dx_e: Sequence[NDArray[floating | complexfloating]] | None = None, ) -> tuple[fdfield_updater_t, fdfield_updater_t, fdfield_updater_t]: """ Utility operators for taking discretized derivatives (backward variant). @@ -36,7 +38,7 @@ def deriv_forward( def deriv_back( - dx_h: Sequence[NDArray[numpy.float_]] | None = None, + dx_h: Sequence[NDArray[floating | complexfloating]] | None = None, ) -> tuple[fdfield_updater_t, fdfield_updater_t, fdfield_updater_t]: """ Utility operators for taking discretized derivatives (forward variant). @@ -59,9 +61,12 @@ def deriv_back( return derivs +TT = TypeVar('TT', bound='NDArray[floating | complexfloating]') + + def curl_forward( - dx_e: Sequence[NDArray[numpy.float_]] | None = None, - ) -> fdfield_updater_t: + dx_e: Sequence[NDArray[floating | complexfloating]] | None = None, + ) -> Callable[[TT], TT]: r""" Curl operator for use with the E field. @@ -75,7 +80,7 @@ def curl_forward( """ Dx, Dy, Dz = deriv_forward(dx_e) - def ce_fun(e: fdfield_t) -> fdfield_t: + def ce_fun(e: TT) -> TT: output = numpy.empty_like(e) output[0] = Dy(e[2]) output[1] = Dz(e[0]) @@ -89,8 +94,8 @@ def curl_forward( def curl_back( - dx_h: Sequence[NDArray[numpy.float_]] | None = None, - ) -> fdfield_updater_t: + dx_h: Sequence[NDArray[floating | complexfloating]] | None = None, + ) -> Callable[[TT], TT]: r""" Create a function which takes the backward curl of a field. @@ -104,7 +109,7 @@ def curl_back( """ Dx, Dy, Dz = deriv_back(dx_h) - def ch_fun(h: fdfield_t) -> fdfield_t: + def ch_fun(h: TT) -> TT: output = numpy.empty_like(h) output[0] = Dy(h[2]) output[1] = Dz(h[0]) @@ -118,11 +123,11 @@ def curl_back( def curl_forward_parts( - dx_e: Sequence[NDArray[numpy.float_]] | None = None, + dx_e: Sequence[NDArray[floating | complexfloating]] | None = None, ) -> Callable: Dx, Dy, Dz = deriv_forward(dx_e) - def mkparts_fwd(e: fdfield_t) -> tuple[tuple[fdfield_t, fdfield_t], ...]: + def mkparts_fwd(e: fdfield) -> tuple[tuple[fdfield, fdfield], ...]: return ((-Dz(e[1]), Dy(e[2])), ( Dz(e[0]), -Dx(e[2])), (-Dy(e[0]), Dx(e[1]))) @@ -131,11 +136,11 @@ def curl_forward_parts( def curl_back_parts( - dx_h: Sequence[NDArray[numpy.float_]] | None = None, + dx_h: Sequence[NDArray[floating | complexfloating]] | None = None, ) -> Callable: Dx, Dy, Dz = deriv_back(dx_h) - def mkparts_back(h: fdfield_t) -> tuple[tuple[fdfield_t, fdfield_t], ...]: + def mkparts_back(h: fdfield) -> tuple[tuple[fdfield, fdfield], ...]: return ((-Dz(h[1]), Dy(h[2])), ( Dz(h[0]), -Dx(h[2])), (-Dy(h[0]), Dx(h[1]))) diff --git a/meanas/fdmath/operators.py b/meanas/fdmath/operators.py index 9d5988d..8b7cabc 100644 --- a/meanas/fdmath/operators.py +++ b/meanas/fdmath/operators.py @@ -3,19 +3,20 @@ Matrix operators for finite difference simulations Basic discrete calculus etc. """ -from typing import Sequence +from collections.abc import Sequence import numpy from numpy.typing import NDArray -import scipy.sparse as sparse # type: ignore +from numpy import floating, complexfloating +from scipy import sparse -from .types import vfdfield_t +from .types import vfdfield def shift_circ( axis: int, shape: Sequence[int], shift_distance: int = 1, - ) -> sparse.spmatrix: + ) -> sparse.sparray: """ Utility operator for performing a circular shift along a specified axis by a specified number of elements. @@ -33,8 +34,8 @@ def shift_circ( if axis not in range(len(shape)): raise Exception(f'Invalid direction: {axis}, shape is {shape}') - shifts = [abs(shift_distance) if a == axis else 0 for a in range(3)] - shifted_diags = [(numpy.arange(n) + s) % n for n, s in zip(shape, shifts)] + shifts = [abs(shift_distance) if a == axis else 0 for a in range(len(shape))] + shifted_diags = [(numpy.arange(n) + s) % n for n, s in zip(shape, shifts, strict=True)] ijk = numpy.meshgrid(*shifted_diags, indexing='ij') n = numpy.prod(shape) @@ -43,7 +44,7 @@ def shift_circ( vij = (numpy.ones(n), (i_ind, j_ind.ravel(order='C'))) - d = sparse.csr_matrix(vij, shape=(n, n)) + d = sparse.csr_array(vij, shape=(n, n)) if shift_distance < 0: d = d.T @@ -55,7 +56,7 @@ def shift_with_mirror( axis: int, shape: Sequence[int], shift_distance: int = 1, - ) -> sparse.spmatrix: + ) -> sparse.sparray: """ Utility operator for performing an n-element shift along a specified axis, with mirror boundary conditions applied to the cells beyond the receding edge. @@ -81,8 +82,8 @@ def shift_with_mirror( v = numpy.where(v < 0, - 1 - v, v) return v - shifts = [shift_distance if a == axis else 0 for a in range(3)] - shifted_diags = [mirrored_range(n, s) for n, s in zip(shape, shifts)] + shifts = [shift_distance if a == axis else 0 for a in range(len(shape))] + shifted_diags = [mirrored_range(n, s) for n, s in zip(shape, shifts, strict=True)] ijk = numpy.meshgrid(*shifted_diags, indexing='ij') n = numpy.prod(shape) @@ -91,13 +92,13 @@ def shift_with_mirror( vij = (numpy.ones(n), (i_ind, j_ind.ravel(order='C'))) - d = sparse.csr_matrix(vij, shape=(n, n)) + d = sparse.csr_array(vij, shape=(n, n)) return d def deriv_forward( - dx_e: Sequence[NDArray[numpy.float_]], - ) -> list[sparse.spmatrix]: + dx_e: Sequence[NDArray[floating | complexfloating]], + ) -> list[sparse.sparray]: """ Utility operators for taking discretized derivatives (forward variant). @@ -113,18 +114,18 @@ def deriv_forward( dx_e_expanded = numpy.meshgrid(*dx_e, indexing='ij') - def deriv(axis: int) -> sparse.spmatrix: - return shift_circ(axis, shape, 1) - sparse.eye(n) + def deriv(axis: int) -> sparse.sparray: + return shift_circ(axis, shape, 1) - sparse.eye_array(n) - Ds = [sparse.diags(+1 / dx.ravel(order='C')) @ deriv(a) + Ds = [sparse.diags_array(+1 / dx.ravel(order='C')) @ deriv(a) for a, dx in enumerate(dx_e_expanded)] return Ds def deriv_back( - dx_h: Sequence[NDArray[numpy.float_]], - ) -> list[sparse.spmatrix]: + dx_h: Sequence[NDArray[floating | complexfloating]], + ) -> list[sparse.sparray]: """ Utility operators for taking discretized derivatives (backward variant). @@ -140,36 +141,37 @@ def deriv_back( dx_h_expanded = numpy.meshgrid(*dx_h, indexing='ij') - def deriv(axis: int) -> sparse.spmatrix: - return shift_circ(axis, shape, -1) - sparse.eye(n) + def deriv(axis: int) -> sparse.sparray: + return shift_circ(axis, shape, -1) - sparse.eye_array(n) - Ds = [sparse.diags(-1 / dx.ravel(order='C')) @ deriv(a) + Ds = [sparse.diags_array(-1 / dx.ravel(order='C')) @ deriv(a) for a, dx in enumerate(dx_h_expanded)] return Ds def cross( - B: Sequence[sparse.spmatrix], - ) -> sparse.spmatrix: + B: Sequence[sparse.sparray], + ) -> sparse.sparray: """ Cross product operator Args: B: List `[Bx, By, Bz]` of sparse matrices corresponding to the x, y, z - portions of the operator on the left side of the cross product. + portions of the operator on the left side of the cross product. Returns: Sparse matrix corresponding to (B x), where x is the cross product. """ n = B[0].shape[0] - zero = sparse.csr_matrix((n, n)) - return sparse.bmat([[zero, -B[2], B[1]], - [B[2], zero, -B[0]], - [-B[1], B[0], zero]]) + zero = sparse.csr_array((n, n)) + return sparse.block_array([ + [zero, -B[2], B[1]], + [B[2], zero, -B[0]], + [-B[1], B[0], zero]]) -def vec_cross(b: vfdfield_t) -> sparse.spmatrix: +def vec_cross(b: vfdfield) -> sparse.sparray: """ Vector cross product operator @@ -181,11 +183,11 @@ def vec_cross(b: vfdfield_t) -> sparse.spmatrix: Sparse matrix corresponding to (b x), where x is the cross product. """ - B = [sparse.diags(c) for c in numpy.split(b, 3)] + B = [sparse.diags_array(c) for c in numpy.split(b, 3)] return cross(B) -def avg_forward(axis: int, shape: Sequence[int]) -> sparse.spmatrix: +def avg_forward(axis: int, shape: Sequence[int]) -> sparse.sparray: """ Forward average operator `(x4 = (x4 + x5) / 2)` @@ -200,10 +202,10 @@ def avg_forward(axis: int, shape: Sequence[int]) -> sparse.spmatrix: raise Exception(f'Invalid shape: {shape}') n = numpy.prod(shape) - return 0.5 * (sparse.eye(n) + shift_circ(axis, shape)) + return 0.5 * (sparse.eye_array(n) + shift_circ(axis, shape)) -def avg_back(axis: int, shape: Sequence[int]) -> sparse.spmatrix: +def avg_back(axis: int, shape: Sequence[int]) -> sparse.sparray: """ Backward average operator `(x4 = (x4 + x3) / 2)` @@ -218,8 +220,8 @@ def avg_back(axis: int, shape: Sequence[int]) -> sparse.spmatrix: def curl_forward( - dx_e: Sequence[NDArray[numpy.float_]], - ) -> sparse.spmatrix: + dx_e: Sequence[NDArray[floating | complexfloating]], + ) -> sparse.sparray: """ Curl operator for use with the E field. @@ -234,8 +236,8 @@ def curl_forward( def curl_back( - dx_h: Sequence[NDArray[numpy.float_]], - ) -> sparse.spmatrix: + dx_h: Sequence[NDArray[floating | complexfloating]], + ) -> sparse.sparray: """ Curl operator for use with the H field. diff --git a/meanas/fdmath/types.py b/meanas/fdmath/types.py index aae9594..b82a5ae 100644 --- a/meanas/fdmath/types.py +++ b/meanas/fdmath/types.py @@ -1,26 +1,65 @@ """ Types shared across multiple submodules """ -from typing import Sequence, Callable, MutableSequence -import numpy +from typing import NewType +from collections.abc import Sequence, Callable, MutableSequence from numpy.typing import NDArray +from numpy import floating, complexfloating # Field types -fdfield_t = NDArray[numpy.float_] +fdfield_t = NewType('fdfield_t', NDArray[floating]) +type fdfield = fdfield_t | NDArray[floating] """Vector field with shape (3, X, Y, Z) (e.g. `[E_x, E_y, E_z]`)""" -vfdfield_t = NDArray[numpy.float_] +vfdfield_t = NewType('vfdfield_t', NDArray[floating]) +type vfdfield = vfdfield_t | NDArray[floating] """Linearized vector field (single vector of length 3*X*Y*Z)""" -cfdfield_t = NDArray[numpy.complex_] +cfdfield_t = NewType('cfdfield_t', NDArray[complexfloating]) +type cfdfield = cfdfield_t | NDArray[complexfloating] """Complex vector field with shape (3, X, Y, Z) (e.g. `[E_x, E_y, E_z]`)""" -vcfdfield_t = NDArray[numpy.complex_] +vcfdfield_t = NewType('vcfdfield_t', NDArray[complexfloating]) +type vcfdfield = vcfdfield_t | NDArray[complexfloating] """Linearized complex vector field (single vector of length 3*X*Y*Z)""" -dx_lists_t = Sequence[Sequence[NDArray[numpy.float_]]] +fdslice_t = NewType('fdslice_t', NDArray[floating]) +type fdslice = fdslice_t | NDArray[floating] +"""Vector field slice with shape (3, X, Y) (e.g. `[E_x, E_y, E_z]` at a single Z position)""" + +vfdslice_t = NewType('vfdslice_t', NDArray[floating]) +type vfdslice = vfdslice_t | NDArray[floating] +"""Linearized vector field slice (single vector of length 3*X*Y)""" + +cfdslice_t = NewType('cfdslice_t', NDArray[complexfloating]) +type cfdslice = cfdslice_t | NDArray[complexfloating] +"""Complex vector field slice with shape (3, X, Y) (e.g. `[E_x, E_y, E_z]` at a single Z position)""" + +vcfdslice_t = NewType('vcfdslice_t', NDArray[complexfloating]) +type vcfdslice = vcfdslice_t | NDArray[complexfloating] +"""Linearized complex vector field slice (single vector of length 3*X*Y)""" + + +fdfield2_t = NewType('fdfield2_t', NDArray[floating]) +type fdfield2 = fdfield2_t | NDArray[floating] +"""2D Vector field with shape (2, X, Y) (e.g. `[E_x, E_y]`)""" + +vfdfield2_t = NewType('vfdfield2_t', NDArray[floating]) +type vfdfield2 = vfdfield2_t | NDArray[floating] +"""2D Linearized vector field (single vector of length 2*X*Y)""" + +cfdfield2_t = NewType('cfdfield2_t', NDArray[complexfloating]) +type cfdfield2 = cfdfield2_t | NDArray[complexfloating] +"""2D Complex vector field with shape (2, X, Y) (e.g. `[E_x, E_y]`)""" + +vcfdfield2_t = NewType('vcfdfield2_t', NDArray[complexfloating]) +type vcfdfield2 = vcfdfield2_t | NDArray[complexfloating] +"""2D Linearized complex vector field (single vector of length 2*X*Y)""" + + +dx_lists_t = Sequence[Sequence[NDArray[floating | complexfloating]]] """ 'dxes' datastructure which contains grid cell width information in the following format: @@ -31,12 +70,26 @@ dx_lists_t = Sequence[Sequence[NDArray[numpy.float_]]] and `dy_h[0]` is the y-width of the `y=0` cells, as used when calculating dH/dy, etc. """ -dx_lists_mut = MutableSequence[MutableSequence[NDArray[numpy.float_]]] +dx_lists2_t = Sequence[Sequence[NDArray[floating | complexfloating]]] +""" + 2D 'dxes' datastructure which contains grid cell width information in the following format: + + [[[dx_e[0], dx_e[1], ...], [dy_e[0], ...]], + [[dx_h[0], dx_h[1], ...], [dy_h[0], ...]]] + + where `dx_e[0]` is the x-width of the `x=0` cells, as used when calculating dE/dx, + and `dy_h[0]` is the y-width of the `y=0` cells, as used when calculating dH/dy, etc. +""" + +dx_lists_mut = MutableSequence[MutableSequence[NDArray[floating | complexfloating]]] """Mutable version of `dx_lists_t`""" +dx_lists2_mut = MutableSequence[MutableSequence[NDArray[floating | complexfloating]]] +"""Mutable version of `dx_lists2_t`""" -fdfield_updater_t = Callable[..., fdfield_t] -"""Convenience type for functions which take and return an fdfield_t""" -cfdfield_updater_t = Callable[..., cfdfield_t] -"""Convenience type for functions which take and return an cfdfield_t""" +fdfield_updater_t = Callable[..., fdfield] +"""Convenience type for functions which take and return a real `fdfield`""" + +cfdfield_updater_t = Callable[..., cfdfield] +"""Convenience type for functions which take and return a complex `cfdfield`""" diff --git a/meanas/fdmath/vectorization.py b/meanas/fdmath/vectorization.py index 0a9f8ad..77b722f 100644 --- a/meanas/fdmath/vectorization.py +++ b/meanas/fdmath/vectorization.py @@ -4,75 +4,122 @@ and a 1D array representation of that field `[f_x0, f_x1, f_x2,... f_y0,... f_z0 Vectorized versions of the field use row-major (ie., C-style) ordering. """ -from typing import overload, Sequence +from typing import overload +from collections.abc import Sequence import numpy -from numpy.typing import ArrayLike +from numpy.typing import ArrayLike, NDArray -from .types import fdfield_t, vfdfield_t, cfdfield_t, vcfdfield_t +from .types import ( + fdfield_t, vfdfield_t, cfdfield_t, vcfdfield_t, + fdslice_t, vfdslice_t, cfdslice_t, vcfdslice_t, + fdfield2_t, vfdfield2_t, cfdfield2_t, vcfdfield2_t, + ) @overload def vec(f: None) -> None: - pass + pass # pragma: no cover @overload def vec(f: fdfield_t) -> vfdfield_t: - pass + pass # pragma: no cover @overload def vec(f: cfdfield_t) -> vcfdfield_t: - pass + pass # pragma: no cover @overload -def vec(f: ArrayLike) -> vfdfield_t | vcfdfield_t: - pass +def vec(f: fdfield2_t) -> vfdfield2_t: + pass # pragma: no cover -def vec(f: fdfield_t | cfdfield_t | ArrayLike | None) -> vfdfield_t | vcfdfield_t | None: +@overload +def vec(f: cfdfield2_t) -> vcfdfield2_t: + pass # pragma: no cover + +@overload +def vec(f: fdslice_t) -> vfdslice_t: + pass # pragma: no cover + +@overload +def vec(f: cfdslice_t) -> vcfdslice_t: + pass # pragma: no cover + +@overload +def vec(f: ArrayLike) -> NDArray: + pass # pragma: no cover + +def vec( + f: fdfield_t | cfdfield_t | fdfield2_t | cfdfield2_t | fdslice_t | cfdslice_t | ArrayLike | None, + ) -> vfdfield_t | vcfdfield_t | vfdfield2_t | vcfdfield2_t | vfdslice_t | vcfdslice_t | NDArray | None: """ - Create a 1D ndarray from a 3D vector field which spans a 1-3D region. + Create a 1D ndarray from a vector field which spans a 1-3D region. Returns `None` if called with `f=None`. Args: - f: A vector field, `[f_x, f_y, f_z]` where each `f_` component is a 1- to - 3-D ndarray (`f_*` should all be the same size). Doesn't fail with `f=None`. + f: A vector field, e.g. `[f_x, f_y, f_z]` where each `f_` component is a 1- to + 3-D ndarray (`f_*` should all be the same size). Doesn't fail with `f=None`. Returns: 1D ndarray containing the linearized field (or `None`) """ if f is None: return None - return numpy.ravel(f, order='C') + return numpy.ravel(f, order='C') # type: ignore @overload -def unvec(v: None, shape: Sequence[int]) -> None: +def unvec(v: None, shape: Sequence[int], nvdim: int = 3) -> None: + pass # pragma: no cover + +@overload +def unvec(v: vfdfield_t, shape: Sequence[int], nvdim: int = 3) -> fdfield_t: + pass # pragma: no cover + +@overload +def unvec(v: vcfdfield_t, shape: Sequence[int], nvdim: int = 3) -> cfdfield_t: + pass # pragma: no cover + +@overload +def unvec(v: vfdfield2_t, shape: Sequence[int], nvdim: int = 3) -> fdfield2_t: pass @overload -def unvec(v: vfdfield_t, shape: Sequence[int]) -> fdfield_t: +def unvec(v: vcfdfield2_t, shape: Sequence[int], nvdim: int = 3) -> cfdfield2_t: pass @overload -def unvec(v: vcfdfield_t, shape: Sequence[int]) -> cfdfield_t: +def unvec(v: vfdslice_t, shape: Sequence[int], nvdim: int = 3) -> fdslice_t: pass -def unvec(v: vfdfield_t | vcfdfield_t | None, shape: Sequence[int]) -> fdfield_t | cfdfield_t | None: +@overload +def unvec(v: vcfdslice_t, shape: Sequence[int], nvdim: int = 3) -> cfdslice_t: + pass + +@overload +def unvec(v: ArrayLike, shape: Sequence[int], nvdim: int = 3) -> NDArray: + pass + +def unvec( + v: vfdfield_t | vcfdfield_t | vfdfield2_t | vcfdfield2_t | vfdslice_t | vcfdslice_t | ArrayLike | None, + shape: Sequence[int], + nvdim: int = 3, + ) -> fdfield_t | cfdfield_t | fdfield2_t | cfdfield2_t | fdslice_t | cfdslice_t | NDArray | None: """ - Perform the inverse of vec(): take a 1D ndarray and output a 3D field - of form `[f_x, f_y, f_z]` where each of `f_*` is a len(shape)-dimensional + Perform the inverse of vec(): take a 1D ndarray and output an `nvdim`-component field + of form e.g. `[f_x, f_y, f_z]` (`nvdim=3`) where each of `f_*` is a len(shape)-dimensional ndarray. Returns `None` if called with `v=None`. Args: - v: 1D ndarray representing a 3D vector field of shape shape (or None) + v: 1D ndarray representing a vector field of shape shape (or None) shape: shape of the vector field + nvdim: Number of components in each vector Returns: `[f_x, f_y, f_z]` where each `f_` is a `len(shape)` dimensional ndarray (or `None`) """ if v is None: return None - return v.reshape((3, *shape), order='C') - + return v.reshape((nvdim, *shape), order='C') # type: ignore diff --git a/meanas/fdtd/__init__.py b/meanas/fdtd/__init__.py index 171c4f4..6291815 100644 --- a/meanas/fdtd/__init__.py +++ b/meanas/fdtd/__init__.py @@ -144,6 +144,50 @@ It is often useful to excite the simulation with an arbitrary broadband pulse an extract the frequency-domain response by performing an on-the-fly Fourier transform of the time-domain fields. +`accumulate_phasor` in `meanas.fdtd.phasor` performs the phase accumulation for one +or more target frequencies, while leaving source normalization and simulation-loop +policy to the caller. `temporal_phasor(...)` and `temporal_phasor_scale(...)` +apply the same Fourier sum to a scalar waveform, which is useful when a pulsed +source envelope must be normalized before being applied to a point source or +mode source. `real_injection_scale(...)` is the corresponding helper for the +common real-valued injection pattern `numpy.real(scale * waveform)`. Convenience +wrappers `accumulate_phasor_e`, `accumulate_phasor_h`, and `accumulate_phasor_j` +apply the usual Yee time offsets. `reconstruct_real(...)` and the corresponding +`reconstruct_real_e/h/j(...)` wrappers perform the inverse operation, converting +phasors back into real-valued field snapshots at explicit Yee-aligned times. +For scalar `omega`, the reconstruction helpers accept either a plain field +phasor or the batched `(1, *sample_shape)` form used by the accumulator helpers. +The helpers accumulate + +$$ \Delta_t \sum_l w_l e^{-i \omega t_l} f_l $$ + +with caller-provided sample times and weights. In this codebase the matching +electric-current convention is typically `E -= dt * J / epsilon` in FDTD and +`-i \omega J` on the right-hand side of the FDFD wave equation. + +For FDTD/FDFD equivalence, this phasor path is the primary comparison workflow. +It isolates the guided `+\omega` response that the frequency-domain solver +targets directly, regardless of whether the underlying FDTD run used real- or +complex-valued fields. + +For exact pulsed FDTD/FDFD equivalence it is often simplest to keep the +injected source, fields, and CPML auxiliary state complex-valued. The +`real_injection_scale(...)` helper is instead for the more ordinary one-run +real-valued source path, where the intended positive-frequency waveform is +injected through `numpy.real(scale * waveform)` and any remaining negative- +frequency leakage is controlled by the pulse bandwidth and run length. + +`reconstruct_real(...)` is for a different question: given a phasor, what late +real-valued field snapshot should it produce? That raw-snapshot comparison is +stricter and noisier because a monitor plane generally contains both the guided +field and the remaining orthogonal content, + +$$ E_{\text{monitor}} = E_{\text{guided}} + E_{\text{residual}} . $$ + +Phasor/modal comparisons mostly validate the guided `+\omega` term. Raw +real-field comparisons expose both terms at once, so they should be treated as +secondary diagnostics rather than the main solver-equivalence benchmark. + The Ricker wavelet (normalized second derivative of a Gaussian) is commonly used for the pulse shape. It can be written @@ -156,11 +200,75 @@ t=0 (assuming the source is off for t<0 this gives $\sim 10^{-3}$ error at t=0). Boundary conditions =================== -# TODO notes about boundaries / PMLs + +`meanas.fdtd` exposes two boundary-related building blocks: + +- `conducting_boundary(...)` for simple perfect-electric-conductor style field + clamping at one face of the domain. +- `cpml_params(...)` and `updates_with_cpml(...)` for convolutional perfectly + matched layers (CPMLs) attached to one or more faces of the Yee grid. + +`updates_with_cpml(...)` accepts a three-by-two table of CPML parameter blocks: + +``` +cpml_params[axis][polarity_index] +``` + +where `axis` is `0`, `1`, or `2` and `polarity_index` corresponds to `(-1, +1)`. +Passing `None` for one entry disables CPML on that face while leaving the other +directions unchanged. This is how mixed boundary setups such as "absorbing in x, +periodic in y/z" are expressed. + +When comparing an FDTD run against an FDFD solve, use the same stretched +coordinate system in both places: + +1. Build the FDTD update with the desired CPML parameters. +2. Stretch the FDFD `dxes` with the matching SCPML transform. +3. Compare the extracted phasor against the FDFD field or residual on those + stretched `dxes`. + +The electric-current sign convention used throughout the examples and tests is + +$$ +E \leftarrow E - \Delta_t J / \epsilon +$$ + +which matches the FDFD right-hand side + +$$ +-i \omega J. +$$ """ -from .base import maxwell_e, maxwell_h -from .pml import cpml_params, updates_with_cpml -from .energy import (poynting, poynting_divergence, energy_hstep, energy_estep, - delta_energy_h2e, delta_energy_j) -from .boundaries import conducting_boundary +from .base import ( + maxwell_e as maxwell_e, + maxwell_h as maxwell_h, + ) +from .pml import ( + cpml_params as cpml_params, + updates_with_cpml as updates_with_cpml, + ) +from .energy import ( + poynting as poynting, + poynting_divergence as poynting_divergence, + energy_hstep as energy_hstep, + energy_estep as energy_estep, + delta_energy_h2e as delta_energy_h2e, + delta_energy_j as delta_energy_j, + ) +from .boundaries import ( + conducting_boundary as conducting_boundary, + ) +from .phasor import ( + accumulate_phasor as accumulate_phasor, + accumulate_phasor_e as accumulate_phasor_e, + accumulate_phasor_h as accumulate_phasor_h, + accumulate_phasor_j as accumulate_phasor_j, + real_injection_scale as real_injection_scale, + reconstruct_real as reconstruct_real, + reconstruct_real_e as reconstruct_real_e, + reconstruct_real_h as reconstruct_real_h, + reconstruct_real_j as reconstruct_real_j, + temporal_phasor as temporal_phasor, + temporal_phasor_scale as temporal_phasor_scale, + ) diff --git a/meanas/fdtd/base.py b/meanas/fdtd/base.py index 3891e28..480ed87 100644 --- a/meanas/fdtd/base.py +++ b/meanas/fdtd/base.py @@ -3,7 +3,7 @@ Basic FDTD field updates """ -from ..fdmath import dx_lists_t, fdfield_t, fdfield_updater_t +from ..fdmath import dx_lists_t, fdfield, fdfield_updater_t from ..fdmath.functional import curl_forward, curl_back @@ -47,7 +47,7 @@ def maxwell_e( else: curl_h_fun = curl_back() - def me_fun(e: fdfield_t, h: fdfield_t, epsilon: fdfield_t | float) -> fdfield_t: + def me_fun(e: fdfield, h: fdfield, epsilon: fdfield | float) -> fdfield: """ Update the E-field. @@ -103,7 +103,7 @@ def maxwell_h( else: curl_e_fun = curl_forward() - def mh_fun(e: fdfield_t, h: fdfield_t, mu: fdfield_t | float | None = None) -> fdfield_t: + def mh_fun(e: fdfield, h: fdfield, mu: fdfield | float | None = None) -> fdfield: """ Update the H-field. diff --git a/meanas/fdtd/boundaries.py b/meanas/fdtd/boundaries.py index 131d741..ca8940d 100644 --- a/meanas/fdtd/boundaries.py +++ b/meanas/fdtd/boundaries.py @@ -6,7 +6,7 @@ Boundary conditions from typing import Any -from ..fdmath import fdfield_t, fdfield_updater_t +from ..fdmath import fdfield, fdfield_updater_t def conducting_boundary( @@ -15,7 +15,7 @@ def conducting_boundary( ) -> tuple[fdfield_updater_t, fdfield_updater_t]: dirs = [0, 1, 2] if direction not in dirs: - raise Exception(f'Invalid direction: {direction}') + raise ValueError(f'Invalid direction: {direction}') dirs.remove(direction) u, v = dirs @@ -28,17 +28,19 @@ def conducting_boundary( shifted1_slice = [slice(None)] * 3 boundary_slice[direction] = 0 shifted1_slice[direction] = 1 + boundary = tuple(boundary_slice) + shifted1 = tuple(shifted1_slice) - def en(e: fdfield_t) -> fdfield_t: - e[direction][boundary_slice] = 0 - e[u][boundary_slice] = e[u][shifted1_slice] - e[v][boundary_slice] = e[v][shifted1_slice] + def en(e: fdfield) -> fdfield: + e[direction][boundary] = 0 + e[u][boundary] = e[u][shifted1] + e[v][boundary] = e[v][shifted1] return e - def hn(h: fdfield_t) -> fdfield_t: - h[direction][boundary_slice] = h[direction][shifted1_slice] - h[u][boundary_slice] = 0 - h[v][boundary_slice] = 0 + def hn(h: fdfield) -> fdfield: + h[direction][boundary] = h[direction][shifted1] + h[u][boundary] = 0 + h[v][boundary] = 0 return h return en, hn @@ -50,22 +52,25 @@ def conducting_boundary( boundary_slice[direction] = -1 shifted1_slice[direction] = -2 shifted2_slice[direction] = -3 + boundary = tuple(boundary_slice) + shifted1 = tuple(shifted1_slice) + shifted2 = tuple(shifted2_slice) - def ep(e: fdfield_t) -> fdfield_t: - e[direction][boundary_slice] = -e[direction][shifted2_slice] - e[direction][shifted1_slice] = 0 - e[u][boundary_slice] = e[u][shifted1_slice] - e[v][boundary_slice] = e[v][shifted1_slice] + def ep(e: fdfield) -> fdfield: + e[direction][boundary] = -e[direction][shifted2] + e[direction][shifted1] = 0 + e[u][boundary] = e[u][shifted1] + e[v][boundary] = e[v][shifted1] return e - def hp(h: fdfield_t) -> fdfield_t: - h[direction][boundary_slice] = h[direction][shifted1_slice] - h[u][boundary_slice] = -h[u][shifted2_slice] - h[u][shifted1_slice] = 0 - h[v][boundary_slice] = -h[v][shifted2_slice] - h[v][shifted1_slice] = 0 + def hp(h: fdfield) -> fdfield: + h[direction][boundary] = h[direction][shifted1] + h[u][boundary] = -h[u][shifted2] + h[u][shifted1] = 0 + h[v][boundary] = -h[v][shifted2] + h[v][shifted1] = 0 return h return ep, hp - raise Exception(f'Bad polarity: {polarity}') + raise ValueError(f'Bad polarity: {polarity}') diff --git a/meanas/fdtd/energy.py b/meanas/fdtd/energy.py index 43ea3a1..57387aa 100644 --- a/meanas/fdtd/energy.py +++ b/meanas/fdtd/energy.py @@ -1,15 +1,29 @@ import numpy -from ..fdmath import dx_lists_t, fdfield_t +from ..fdmath import dx_lists_t, fdfield_t, fdfield from ..fdmath.functional import deriv_back -# TODO documentation +""" +Energy- and flux-accounting helpers for Yee-grid FDTD fields. + +These functions complement the derivation in `meanas.fdtd`: + +- `poynting(...)` and `poynting_divergence(...)` evaluate the discrete flux terms + from the exact time-domain Poynting identity. +- `energy_hstep(...)` / `energy_estep(...)` evaluate the two staggered energy + expressions. +- `delta_energy_*` helpers evaluate the corresponding energy changes between + adjacent half-steps. + +The helpers are intended for diagnostics, regression tests, and consistency +checks between source work, field energy, and flux through cell faces. +""" def poynting( - e: fdfield_t, - h: fdfield_t, + e: fdfield, + h: fdfield, dxes: dx_lists_t | None = None, ) -> fdfield_t: r""" @@ -43,6 +57,7 @@ def poynting( (see `meanas.tests.test_fdtd.test_poynting_planes`) The full relationship is + $$ \begin{aligned} (U_{l+\frac{1}{2}} - U_l) / \Delta_t @@ -84,14 +99,14 @@ def poynting( s[0] = numpy.roll(ey, -1, axis=0) * hz - numpy.roll(ez, -1, axis=0) * hy s[1] = numpy.roll(ez, -1, axis=1) * hx - numpy.roll(ex, -1, axis=1) * hz s[2] = numpy.roll(ex, -1, axis=2) * hy - numpy.roll(ey, -1, axis=2) * hx - return s + return fdfield_t(s) def poynting_divergence( - s: fdfield_t | None = None, + s: fdfield | None = None, *, - e: fdfield_t | None = None, - h: fdfield_t | None = None, + e: fdfield | None = None, + h: fdfield | None = None, dxes: dx_lists_t | None = None, ) -> fdfield_t: """ @@ -122,15 +137,15 @@ def poynting_divergence( Dx, Dy, Dz = deriv_back() ds = Dx(s[0]) + Dy(s[1]) + Dz(s[2]) - return ds + return fdfield_t(ds) def energy_hstep( - e0: fdfield_t, - h1: fdfield_t, - e2: fdfield_t, - epsilon: fdfield_t | None = None, - mu: fdfield_t | None = None, + e0: fdfield, + h1: fdfield, + e2: fdfield, + epsilon: fdfield | None = None, + mu: fdfield | None = None, dxes: dx_lists_t | None = None, ) -> fdfield_t: """ @@ -150,15 +165,15 @@ def energy_hstep( Energy, at the time of the H-field `h1`. """ u = dxmul(e0 * e2, h1 * h1, epsilon, mu, dxes) - return u + return fdfield_t(u) def energy_estep( - h0: fdfield_t, - e1: fdfield_t, - h2: fdfield_t, - epsilon: fdfield_t | None = None, - mu: fdfield_t | None = None, + h0: fdfield, + e1: fdfield, + h2: fdfield, + epsilon: fdfield | None = None, + mu: fdfield | None = None, dxes: dx_lists_t | None = None, ) -> fdfield_t: """ @@ -178,17 +193,17 @@ def energy_estep( Energy, at the time of the E-field `e1`. """ u = dxmul(e1 * e1, h0 * h2, epsilon, mu, dxes) - return u + return fdfield_t(u) def delta_energy_h2e( dt: float, - e0: fdfield_t, - h1: fdfield_t, - e2: fdfield_t, - h3: fdfield_t, - epsilon: fdfield_t | None = None, - mu: fdfield_t | None = None, + e0: fdfield, + h1: fdfield, + e2: fdfield, + h3: fdfield, + epsilon: fdfield | None = None, + mu: fdfield | None = None, dxes: dx_lists_t | None = None, ) -> fdfield_t: """ @@ -211,17 +226,17 @@ def delta_energy_h2e( de = e2 * (e2 - e0) / dt dh = h1 * (h3 - h1) / dt du = dxmul(de, dh, epsilon, mu, dxes) - return du + return fdfield_t(du) def delta_energy_e2h( dt: float, - h0: fdfield_t, - e1: fdfield_t, - h2: fdfield_t, - e3: fdfield_t, - epsilon: fdfield_t | None = None, - mu: fdfield_t | None = None, + h0: fdfield, + e1: fdfield, + h2: fdfield, + e3: fdfield, + epsilon: fdfield | None = None, + mu: fdfield | None = None, dxes: dx_lists_t | None = None, ) -> fdfield_t: """ @@ -244,21 +259,31 @@ def delta_energy_e2h( de = e1 * (e3 - e1) / dt dh = h2 * (h2 - h0) / dt du = dxmul(de, dh, epsilon, mu, dxes) - return du + return fdfield_t(du) def delta_energy_j( - j0: fdfield_t, - e1: fdfield_t, + j0: fdfield, + e1: fdfield, dxes: dx_lists_t | None = None, ) -> fdfield_t: - """ - Calculate + r""" + Calculate the electric-current work term $J \cdot E$ on the Yee grid. - Note that each value of $J$ contributes to the energy twice (i.e. once per field update) - despite only causing the value of $E$ to change once (same for $M$ and $H$). + This is the source contribution that appears beside the flux divergence in + the discrete Poynting identities documented in `meanas.fdtd`. + Note that each value of `J` contributes twice in a full Yee cycle (once per + half-step energy balance) even though it directly changes `E` only once. + Args: + j0: Electric-current density sampled at the same half-step as the + current work term. + e1: Electric field sampled at the matching integer timestep. + dxes: Grid description; defaults to unit spacing. + + Returns: + Per-cell source-work contribution with the scalar field shape. """ if dxes is None: dxes = tuple(tuple(numpy.ones(1) for _ in range(3)) for _ in range(2)) @@ -267,16 +292,30 @@ def delta_energy_j( * dxes[0][0][:, None, None] * dxes[0][1][None, :, None] * dxes[0][2][None, None, :]) - return du + return fdfield_t(du) def dxmul( - ee: fdfield_t, - hh: fdfield_t, - epsilon: fdfield_t | float | None = None, - mu: fdfield_t | float | None = None, + ee: fdfield, + hh: fdfield, + epsilon: fdfield | float | None = None, + mu: fdfield | float | None = None, dxes: dx_lists_t | None = None, ) -> fdfield_t: + """ + Multiply E- and H-like field products by material weights and cell volumes. + + Args: + ee: Three-component electric-field product, such as `e0 * e2`. + hh: Three-component magnetic-field product, such as `h1 * h1`. + epsilon: Electric material weight; defaults to `1`. + mu: Magnetic material weight; defaults to `1`. + dxes: Grid description; defaults to unit spacing. + + Returns: + Scalar field containing the weighted electric plus magnetic contribution + for each Yee cell. + """ if epsilon is None: epsilon = 1 if mu is None: @@ -292,4 +331,4 @@ def dxmul( * dxes[1][0][:, None, None] * dxes[1][1][None, :, None] * dxes[1][2][None, None, :]) - return result + return fdfield_t(result) diff --git a/meanas/fdtd/misc.py b/meanas/fdtd/misc.py new file mode 100644 index 0000000..585c745 --- /dev/null +++ b/meanas/fdtd/misc.py @@ -0,0 +1,180 @@ +from collections.abc import Callable +import logging +from typing import cast + +import numpy +from numpy.typing import NDArray, ArrayLike +from numpy import pi + + +logger = logging.getLogger(__name__) + + +type pulse_scalar_t = float | NDArray[numpy.floating] +pulse_fn_t = Callable[[ArrayLike], tuple[pulse_scalar_t, pulse_scalar_t, pulse_scalar_t]] + + +def _scalar_or_array(values: NDArray[numpy.floating]) -> pulse_scalar_t: + if values.ndim == 0: + return float(values) + return cast('NDArray[numpy.floating]', values) + + +def gaussian_packet( + wl: float, + dwl: float, + dt: float, + turn_on: float = 1e-10, + one_sided: bool = False, + ) -> tuple[pulse_fn_t, float]: + """ + Gaussian pulse (or gaussian ramp) for FDTD excitation + + exp(-a*t*t) ==> exp(-omega * omega / (4 * a)) [fourier, ignoring leading const.] + + FWHM_time is 2 * sqrt(2 * log(2)) * sqrt(2 / a) + FWHM_omega is 2 * sqrt(2 * log(2)) * sqrt(2 * a) = 4 * sqrt(log(2) * a) + + Args: + wl: wavelength + dwl: Gaussian's FWHM in wavelength space + dt: Timestep + turn_on: Max allowable amplitude at t=0 + one_sided: If `True`, source amplitude never decreases after reaching max + + Returns: + Source function: src(timestep) -> (envelope[tt], cos[... * tt], sin[... * tt]) + Delay: number of initial timesteps for which envelope[tt] will be 0 + """ + logger.warning('meanas.fdtd.misc functions are still very WIP!') # TODO + # dt * dw = 4 * ln(2) + + omega = 2 * pi / wl + freq = 1 / wl + fwhm_omega = dwl * omega * omega / (2 * pi) # dwl -> d_omega (approx) + alpha = (fwhm_omega * fwhm_omega) * numpy.log(2) / 8 + delay = numpy.sqrt(-numpy.log(turn_on) / alpha) + delay = numpy.ceil(delay * freq) / freq # force delay to integer number of periods to maintain phase + logger.info(f'src_time {2 * delay / dt}') + + def source_phasor(ii: ArrayLike) -> tuple[pulse_scalar_t, pulse_scalar_t, pulse_scalar_t]: + ii_array = numpy.asarray(ii, dtype=float) + t0 = ii_array * dt - delay + envelope = numpy.sqrt(numpy.sqrt(2 * alpha / pi)) * numpy.exp(-alpha * t0 * t0) + + if one_sided: + envelope = numpy.where(t0 > 0, 1.0, envelope) + + cc = numpy.cos(omega * t0) + ss = numpy.sin(omega * t0) + + return _scalar_or_array(envelope), _scalar_or_array(cc), _scalar_or_array(ss) + + # nrm = numpy.exp(-omega * omega / alpha) / 2 + + return source_phasor, delay + + +def ricker_pulse( + wl: float, + dt: float, + turn_on: float = 1e-10, + ) -> tuple[pulse_fn_t, float]: + """ + Ricker wavelet (second derivative of a gaussian pulse) + + t0 = ii * dt - delay + R = w_peak * t0 / 2 + f(t) = (1 - 2 * (pi * f_peak * t0) ** 2) * exp(-(pi * f_peak * t0)**2 + = (1 - (w_peak * t0)**2 / 2 exp(-(w_peak * t0 / 2) **2) + = (1 - 2 * R * R) * exp(-R * R) + + # NOTE: don't use cosine/sine for J, just for phasor readout + + Args: + wl: wavelength + dt: Timestep + turn_on: Max allowable amplitude at t=0 + + Returns: + Source function: src(timestep) -> (envelope[tt], cos[... * tt], sin[... * tt]) + Delay: number of initial timesteps for which envelope[tt] will be 0 + """ + logger.warning('meanas.fdtd.misc functions are still very WIP!') # TODO + omega = 2 * pi / wl + freq = 1 / wl + + from scipy.optimize import root_scalar + delay_results = root_scalar( + lambda tt: (1 - omega * omega * tt * tt / 2) * numpy.exp(-omega * omega * tt * tt / 4) - turn_on, + x0=0, + x1=-2 / omega, + ) + + delay = delay_results.root + delay = numpy.ceil(delay * freq) / freq # force delay to integer number of periods to maintain phase + + def source_phasor(ii: ArrayLike) -> tuple[pulse_scalar_t, pulse_scalar_t, pulse_scalar_t]: + ii_array = numpy.asarray(ii, dtype=float) + t0 = ii_array * dt - delay + rr = omega * t0 / 2 + ff = (1 - 2 * rr * rr) * numpy.exp(-rr * rr) + + cc = numpy.cos(omega * t0) + ss = numpy.sin(omega * t0) + + return _scalar_or_array(ff), _scalar_or_array(cc), _scalar_or_array(ss) + + return source_phasor, delay + + +def gaussian_beam( + xyz: list[NDArray], + center: ArrayLike, + waist_radius: float, + wl: float, + tilt: float = 0, + ) -> NDArray[numpy.complex128]: + """ + Gaussian beam + (solution to paraxial Helmholtz equation) + + Default (no tilt) corresponds to a beam propagating in the -z direction. + + Args: + xyz: List of [[x0, x1, ...], [y0, ...], [z0, ...]] positions specifying grid + locations at which the field will be sampled. + center: [x, y, z] location of beam waist + waist_radius: Beam radius at the waist + wl: Wavelength + tilt: Rotation around y axis. Default (0) has beam propagating in -z direction. + """ + logger.warning('meanas.fdtd.misc functions are still very WIP!') # TODO + w0 = waist_radius + grids = numpy.asarray(numpy.meshgrid(*xyz, indexing='ij')) + grids -= numpy.asarray(center)[:, None, None, None] + + rot = numpy.array([ + [ numpy.cos(tilt), 0, numpy.sin(tilt)], + [ 0, 1, 0], + [-numpy.sin(tilt), 0, numpy.cos(tilt)], + ]) + + xx, yy, zz = numpy.einsum('ij,jxyz->ixyz', rot, grids) + r2 = xx * xx + yy * yy + z2 = zz * zz + + zr = pi * w0 * w0 / wl + zr2 = zr * zr + wz2 = w0 * w0 * (1 + z2 / zr2) + wz = numpy.sqrt(wz2) # == fwhm(z) / sqrt(2 * ln(2)) + + kk = 2 * pi / wl + inv_Rz = numpy.divide(zz, z2 + zr2, out=numpy.zeros_like(zz), where=(z2 + zr2) != 0) + gouy = numpy.arctan(zz / zr) + + gaussian = w0 / wz * numpy.exp(-r2 / wz2) * numpy.exp(1j * (kk * zz + kk * r2 * inv_Rz / 2 - gouy)) + + row = gaussian[:, :, gaussian.shape[2] // 2] + norm = numpy.linalg.norm(row) + return gaussian / norm diff --git a/meanas/fdtd/phasor.py b/meanas/fdtd/phasor.py new file mode 100644 index 0000000..d5a01cd --- /dev/null +++ b/meanas/fdtd/phasor.py @@ -0,0 +1,319 @@ +""" +Helpers for extracting single- or multi-frequency phasors from FDTD samples. + +These helpers are intentionally low-level: callers own the accumulator arrays and +the sampling policy. The accumulated quantity is + + dt * sum(weight * exp(-1j * omega * t_step) * sample_step) + +where `t_step = (step + offset_steps) * dt`. + +The usual Yee offsets are: + +- `accumulate_phasor_e(..., step=l)` for `E_l` +- `accumulate_phasor_h(..., step=l)` for `H_{l + 1/2}` +- `accumulate_phasor_j(..., step=l)` for `J_{l + 1/2}` + +`temporal_phasor(...)` and `temporal_phasor_scale(...)` apply the same Fourier +sum to a 1D scalar waveform. They are useful for normalizing a pulsed source +before that scalar waveform is applied to a point source or spatial mode source. +`real_injection_scale(...)` is a companion helper for the common real-valued +injection pattern `numpy.real(scale * waveform)`, where `waveform` is the +analytic positive-frequency signal and the injected real current should still +produce a desired phasor response. +`reconstruct_real(...)` and its `E/H/J` wrappers perform the inverse operation: +they turn one or more phasors back into real-valued field snapshots at explicit +Yee-aligned sample times. For a scalar target frequency they accept either a +plain field phasor or the batched `(1, *sample_shape)` form used elsewhere in +this module. + +These helpers do not choose warmup/accumulation windows or pulse-envelope +normalization. They also do not impose a current sign convention. In this +codebase, electric-current injection normally appears as `E -= dt * J / epsilon`, +which matches the FDFD right-hand side `-1j * omega * J`. +""" +from collections.abc import Sequence + +import numpy +from numpy.typing import ArrayLike, NDArray + + +def _normalize_omegas( + omegas: float | complex | Sequence[float | complex] | NDArray, + ) -> NDArray[numpy.complexfloating]: + omega_array = numpy.atleast_1d(numpy.asarray(omegas, dtype=complex)) + if omega_array.ndim != 1 or omega_array.size == 0: + raise ValueError('omegas must be a scalar or non-empty 1D sequence') + return omega_array + + +def _normalize_weight( + weight: ArrayLike, + omega_shape: tuple[int, ...], + ) -> NDArray[numpy.complexfloating]: + weight_array = numpy.asarray(weight, dtype=complex) + if weight_array.ndim == 0: + return numpy.full(omega_shape, weight_array, dtype=complex) + if weight_array.shape == omega_shape: + return weight_array + raise ValueError(f'weight must be scalar or have shape {omega_shape}, got {weight_array.shape}') + + +def _normalize_temporal_samples( + samples: ArrayLike, + ) -> NDArray[numpy.complexfloating]: + sample_array = numpy.asarray(samples, dtype=complex) + if sample_array.ndim != 1 or sample_array.size == 0: + raise ValueError('samples must be a non-empty 1D sequence') + return sample_array + + +def _validate_reconstruction_inputs( + phasors: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + ) -> tuple[NDArray[numpy.complexfloating], NDArray[numpy.complexfloating], bool]: + if dt <= 0: + raise ValueError('dt must be positive') + + omega_array = _normalize_omegas(omegas) + phasor_array = numpy.asarray(phasors, dtype=complex) + expected_leading = omega_array.size + if phasor_array.ndim == 0: + raise ValueError( + f'phasors must have shape ({expected_leading}, *sample_shape) or sample_shape for scalar omega, got {phasor_array.shape}', + ) + added_axis = False + if expected_leading == 1 and (phasor_array.ndim == 1 or phasor_array.shape[0] != expected_leading): + phasor_array = phasor_array[numpy.newaxis, ...] + added_axis = True + elif phasor_array.shape[0] != expected_leading: + raise ValueError( + f'phasors must have shape ({expected_leading}, *sample_shape) or sample_shape for scalar omega, got {phasor_array.shape}', + ) + return omega_array, phasor_array, added_axis + + +def accumulate_phasor( + accumulator: NDArray[numpy.complexfloating], + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + sample: ArrayLike, + step: int, + *, + offset_steps: float = 0.0, + weight: ArrayLike = 1.0, + ) -> NDArray[numpy.complexfloating]: + """ + Add one time-domain sample into a phasor accumulator. + + The added quantity is + + dt * weight * exp(-1j * omega * t_step) * sample + + where `t_step = (step + offset_steps) * dt`. + + Note: + This helper already multiplies by `dt`. If the caller's normalization + factor was derived from a discrete sum that already includes `dt`, pass + `weight / dt` here. + """ + if dt <= 0: + raise ValueError('dt must be positive') + + omega_array = _normalize_omegas(omegas) + sample_array = numpy.asarray(sample) + expected_shape = (omega_array.size, *sample_array.shape) + if accumulator.shape != expected_shape: + raise ValueError(f'accumulator must have shape {expected_shape}, got {accumulator.shape}') + + weight_array = _normalize_weight(weight, omega_array.shape) + time = (step + offset_steps) * dt + phase = numpy.exp(-1j * omega_array * time) + scaled = dt * (weight_array * phase).reshape((-1,) + (1,) * sample_array.ndim) + accumulator += scaled * sample_array + return accumulator + + +def temporal_phasor( + samples: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + *, + start_step: int = 0, + offset_steps: float = 0.0, + ) -> NDArray[numpy.complexfloating]: + """ + Fourier-project a 1D temporal waveform onto one or more angular frequencies. + + The returned quantity is + + dt * sum(exp(-1j * omega * t_step) * samples[step_index]) + + where `t_step = (start_step + step_index + offset_steps) * dt`. + """ + if dt <= 0: + raise ValueError('dt must be positive') + + omega_array = _normalize_omegas(omegas) + sample_array = _normalize_temporal_samples(samples) + steps = start_step + numpy.arange(sample_array.size, dtype=float) + offset_steps + phase = numpy.exp(-1j * omega_array[:, None] * (steps[None, :] * dt)) + return dt * (phase @ sample_array) + + +def temporal_phasor_scale( + samples: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + *, + start_step: int = 0, + offset_steps: float = 0.0, + target: ArrayLike = 1.0, + ) -> NDArray[numpy.complexfloating]: + """ + Return the scalar multiplier that gives a desired temporal phasor response. + + The returned scale satisfies + + temporal_phasor(scale * samples, omegas, dt, ...) == target + + for each target frequency. The result keeps a leading frequency axis even + when `omegas` is scalar. + """ + response = temporal_phasor(samples, omegas, dt, start_step=start_step, offset_steps=offset_steps) + target_array = _normalize_weight(target, response.shape) + if numpy.any(numpy.abs(response) <= numpy.finfo(float).eps): + raise ValueError('cannot normalize a waveform with zero temporal phasor response') + return target_array / response + + +def real_injection_scale( + samples: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + *, + start_step: int = 0, + offset_steps: float = 0.0, + target: ArrayLike = 1.0, + ) -> NDArray[numpy.complexfloating]: + """ + Return the scale for a real-valued injection built from an analytic waveform. + + If the time-domain source is applied as + + numpy.real(scale * samples[step]) + + then the desired positive-frequency phasor is obtained by compensating for + the 1/2 factor between the real-valued source and its analytic component: + + scale = 2 * target / temporal_phasor(samples, ...) + + This helper normalizes only the intended positive-frequency component. Any + residual negative-frequency leakage is controlled by the waveform design and + the accumulation window. + """ + response = temporal_phasor(samples, omegas, dt, start_step=start_step, offset_steps=offset_steps) + target_array = _normalize_weight(target, response.shape) + if numpy.any(numpy.abs(response) <= numpy.finfo(float).eps): + raise ValueError('cannot normalize a waveform with zero temporal phasor response') + return 2 * target_array / response + + +def reconstruct_real( + phasors: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + step: int, + *, + offset_steps: float = 0.0, + ) -> NDArray[numpy.floating]: + """ + Reconstruct a real-valued field snapshot from one or more phasors. + + The returned quantity is + + real(phasor * exp(1j * omega * t_step)) + + where `t_step = (step + offset_steps) * dt`. + + For multi-frequency inputs, the leading frequency axis is preserved. For a + scalar `omega`, callers may pass either `(1, *sample_shape)` or + `sample_shape`; the return shape matches that choice. + """ + omega_array, phasor_array, added_axis = _validate_reconstruction_inputs(phasors, omegas, dt) + time = (step + offset_steps) * dt + phase = numpy.exp(1j * omega_array * time).reshape((-1,) + (1,) * (phasor_array.ndim - 1)) + reconstructed = numpy.real(phasor_array * phase) + if added_axis: + return reconstructed[0] + return reconstructed + + +def accumulate_phasor_e( + accumulator: NDArray[numpy.complexfloating], + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + sample: ArrayLike, + step: int, + *, + weight: ArrayLike = 1.0, + ) -> NDArray[numpy.complexfloating]: + """Accumulate an E-field sample taken at integer timestep `step`.""" + return accumulate_phasor(accumulator, omegas, dt, sample, step, offset_steps=0.0, weight=weight) + + +def accumulate_phasor_h( + accumulator: NDArray[numpy.complexfloating], + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + sample: ArrayLike, + step: int, + *, + weight: ArrayLike = 1.0, + ) -> NDArray[numpy.complexfloating]: + """Accumulate an H-field sample corresponding to `H_{step + 1/2}`.""" + return accumulate_phasor(accumulator, omegas, dt, sample, step, offset_steps=0.5, weight=weight) + + +def accumulate_phasor_j( + accumulator: NDArray[numpy.complexfloating], + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + sample: ArrayLike, + step: int, + *, + weight: ArrayLike = 1.0, + ) -> NDArray[numpy.complexfloating]: + """Accumulate a current sample corresponding to `J_{step + 1/2}`.""" + return accumulate_phasor(accumulator, omegas, dt, sample, step, offset_steps=0.5, weight=weight) + + +def reconstruct_real_e( + phasors: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + step: int, + ) -> NDArray[numpy.floating]: + """Reconstruct a real E-field snapshot taken at integer timestep `step`.""" + return reconstruct_real(phasors, omegas, dt, step, offset_steps=0.0) + + +def reconstruct_real_h( + phasors: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + step: int, + ) -> NDArray[numpy.floating]: + """Reconstruct a real H-field snapshot corresponding to `H_{step + 1/2}`.""" + return reconstruct_real(phasors, omegas, dt, step, offset_steps=0.5) + + +def reconstruct_real_j( + phasors: ArrayLike, + omegas: float | complex | Sequence[float | complex] | NDArray, + dt: float, + step: int, + ) -> NDArray[numpy.floating]: + """Reconstruct a real current snapshot corresponding to `J_{step + 1/2}`.""" + return reconstruct_real(phasors, omegas, dt, step, offset_steps=0.5) diff --git a/meanas/fdtd/pml.py b/meanas/fdtd/pml.py index 65d71e6..aba9cb7 100644 --- a/meanas/fdtd/pml.py +++ b/meanas/fdtd/pml.py @@ -1,18 +1,29 @@ """ -PML implementations +Convolutional perfectly matched layer (CPML) support for FDTD updates. -#TODO discussion of PMLs -#TODO cpml documentation +The helpers in this module construct per-face CPML parameters and then wrap the +standard Yee updates with the additional auxiliary `psi` fields needed by the +CPML recurrence. +The intended call pattern is: + +1. Build a `cpml_params[axis][polarity_index]` table with `cpml_params(...)`. +2. Pass that table into `updates_with_cpml(...)` together with `dt`, `dxes`, and + `epsilon`. +3. Advance the returned `update_E` / `update_H` closures in the simulation loop. + +Each face can be enabled or disabled independently by replacing one table entry +with `None`. """ # TODO retest pmls! -from typing import Callable, Sequence, Any +from typing import Any +from collections.abc import Callable, Sequence from copy import deepcopy import numpy from numpy.typing import NDArray, DTypeLike -from ..fdmath import fdfield_t, dx_lists_t +from ..fdmath import fdfield, dx_lists_t from ..fdmath.functional import deriv_forward, deriv_back @@ -31,18 +42,41 @@ def cpml_params( ma: float = 1, cfs_alpha: float = 0, ) -> dict[str, Any]: + """ + Construct the parameter block for one CPML face. + + Args: + axis: Which Cartesian axis the CPML is normal to (`0`, `1`, or `2`). + polarity: Which face along that axis (`-1` for the low-index face, + `+1` for the high-index face). + dt: Timestep used by the Yee update. + thickness: Number of Yee cells occupied by the CPML region. + ln_R_per_layer: Logarithmic attenuation target per layer. + epsilon_eff: Effective permittivity used when choosing the CPML scaling. + mu_eff: Effective permeability used when choosing the CPML scaling. + m: Polynomial grading exponent for `sigma` and `kappa`. + ma: Polynomial grading exponent for the complex-frequency shift `alpha`. + cfs_alpha: Maximum complex-frequency shift parameter. + + Returns: + Dictionary with: + + - `param_e`: `(p0, p1, p2)` arrays for the E update + - `param_h`: `(p0, p1, p2)` arrays for the H update + - `region`: slice tuple selecting the CPML cells on that face + """ if axis not in range(3): - raise Exception(f'Invalid axis: {axis}') + raise ValueError(f'Invalid axis: {axis}') if polarity not in (-1, 1): - raise Exception(f'Invalid polarity: {polarity}') + raise ValueError(f'Invalid polarity: {polarity}') if thickness <= 2: - raise Exception('It would be wise to have a pml with 4+ cells of thickness') + raise ValueError('It would be wise to have a pml with 4+ cells of thickness') if epsilon_eff <= 0: - raise Exception('epsilon_eff must be positive') + raise ValueError('epsilon_eff must be positive') sigma_max = -ln_R_per_layer / 2 * (m + 1) kappa_max = numpy.sqrt(epsilon_eff * mu_eff) @@ -56,8 +90,6 @@ def cpml_params( xh -= 0.5 xe = xe[::-1] xh = xh[::-1] - else: - raise Exception('Bad polarity!') expand_slice_l: list[Any] = [None, None, None] expand_slice_l[axis] = slice(None) @@ -81,8 +113,6 @@ def cpml_params( region_list[axis] = slice(None, thickness) elif polarity > 0: region_list[axis] = slice(-thickness, None) - else: - raise Exception('Bad polarity!') region = tuple(region_list) return { @@ -96,11 +126,31 @@ def updates_with_cpml( cpml_params: Sequence[Sequence[dict[str, Any] | None]], dt: float, dxes: dx_lists_t, - epsilon: fdfield_t, + epsilon: fdfield, *, dtype: DTypeLike = numpy.float32, - ) -> tuple[Callable[[fdfield_t, fdfield_t, fdfield_t], None], - Callable[[fdfield_t, fdfield_t, fdfield_t], None]]: + ) -> tuple[Callable[..., None], Callable[..., None]]: + """ + Build Yee-step update closures augmented with CPML terms. + + Args: + cpml_params: Three-by-two sequence indexed as `[axis][polarity_index]`. + Entries are the dictionaries returned by `cpml_params(...)`; use + `None` to disable CPML on one face. + dt: Timestep. + dxes: Yee-grid spacing lists `[dx_e, dx_h]`. + epsilon: Electric material distribution used by the E update. + dtype: Storage dtype for the auxiliary CPML state arrays. + + Returns: + `(update_E, update_H)` closures with the same call shape as the basic + Yee updates: + + - `update_E(e, h, epsilon)` + - `update_H(e, h, mu)` + + The closures retain the CPML auxiliary state internally. + """ Dfx, Dfy, Dfz = deriv_forward(dxes[1]) Dbx, Dby, Dbz = deriv_back(dxes[1]) @@ -111,7 +161,7 @@ def updates_with_cpml( params_H: list[list[tuple[Any, Any, Any, Any]]] = deepcopy(params_E) for axis in range(3): - for pp, polarity in enumerate((-1, 1)): + for pp, _polarity in enumerate((-1, 1)): cpml_param = cpml_params[axis][pp] if cpml_param is None: psi_E[axis][pp] = (None, None) @@ -136,9 +186,9 @@ def updates_with_cpml( pH = numpy.empty_like(epsilon, dtype=dtype) def update_E( - e: fdfield_t, - h: fdfield_t, - epsilon: fdfield_t, + e: fdfield, + h: fdfield, + epsilon: fdfield, ) -> None: dyHx = Dby(h[0]) dzHx = Dbz(h[0]) @@ -182,9 +232,9 @@ def updates_with_cpml( e[2] += dt / epsilon[2] * (dxHy - dyHx + pE[2]) def update_H( - e: fdfield_t, - h: fdfield_t, - mu: fdfield_t = numpy.ones(3), + e: fdfield, + h: fdfield, + mu: fdfield | tuple[int, int, int] = (1, 1, 1), ) -> None: dyEx = Dfy(e[0]) dzEx = Dfz(e[0]) diff --git a/meanas/test/_bloch_case.py b/meanas/test/_bloch_case.py new file mode 100644 index 0000000..430cd06 --- /dev/null +++ b/meanas/test/_bloch_case.py @@ -0,0 +1,37 @@ +import numpy + + +SHAPE = (2, 2, 2) +G_MATRIX = numpy.eye(3) +K0_GENERAL = numpy.array([0.1, 0.2, 0.3], dtype=float) +K0_AXIAL = numpy.array([0.0, 0.0, 0.25], dtype=float) +K0_X = numpy.array([0.1, 0.0, 0.0], dtype=float) +EPSILON = numpy.ones((3, *SHAPE), dtype=float) +MU = numpy.stack([ + numpy.linspace(2.0, 2.7, numpy.prod(SHAPE)).reshape(SHAPE), + numpy.linspace(2.1, 2.8, numpy.prod(SHAPE)).reshape(SHAPE), + numpy.linspace(2.2, 2.9, numpy.prod(SHAPE)).reshape(SHAPE), +]) +H_SIZE = 2 * numpy.prod(SHAPE) +H_MN = (numpy.arange(H_SIZE) + 0.25j).astype(complex) +ZERO_H_MN = numpy.zeros_like(H_MN) +Y0 = (numpy.arange(H_SIZE, dtype=float) + 1j * numpy.linspace(0.1, 0.9, H_SIZE))[None, :] +Y0_TWO_MODE = numpy.vstack( + [ + numpy.arange(H_SIZE, dtype=float) + 1j * numpy.linspace(0.1, 0.9, H_SIZE), + numpy.linspace(2.0, 3.5, H_SIZE) - 0.5j * numpy.arange(H_SIZE, dtype=float), + ], +) + + +def build_overlap_fixture() -> tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]: + e_in = numpy.zeros((3, *SHAPE), dtype=complex) + h_in = numpy.zeros_like(e_in) + e_out = numpy.zeros_like(e_in) + h_out = numpy.zeros_like(e_in) + + e_in[1] = 1.0 + h_in[2] = 2.0 + e_out[1] = 3.0 + h_out[2] = 4.0 + return e_in, h_in, e_out, h_out diff --git a/meanas/test/_fdfd_case.py b/meanas/test/_fdfd_case.py new file mode 100644 index 0000000..35284f6 --- /dev/null +++ b/meanas/test/_fdfd_case.py @@ -0,0 +1,49 @@ +import numpy + +from ..fdmath import vec, unvec + + +OMEGA = 1 / 1500 +SHAPE = (2, 3, 2) +DXES = [ + [numpy.array([1.0, 1.5]), numpy.array([0.75, 1.25, 1.5]), numpy.array([1.2, 0.8])], + [numpy.array([0.9, 1.4]), numpy.array([0.8, 1.1, 1.4]), numpy.array([1.0, 0.7])], +] + +EPSILON = numpy.stack([ + numpy.linspace(1.0, 2.2, numpy.prod(SHAPE)).reshape(SHAPE), + numpy.linspace(1.1, 2.3, numpy.prod(SHAPE)).reshape(SHAPE), + numpy.linspace(1.2, 2.4, numpy.prod(SHAPE)).reshape(SHAPE), +]) +MU = numpy.stack([ + numpy.linspace(2.0, 3.2, numpy.prod(SHAPE)).reshape(SHAPE), + numpy.linspace(2.1, 3.3, numpy.prod(SHAPE)).reshape(SHAPE), + numpy.linspace(2.2, 3.4, numpy.prod(SHAPE)).reshape(SHAPE), +]) + +E_FIELD = (numpy.arange(3 * numpy.prod(SHAPE)).reshape((3, *SHAPE)) + 0.5j).astype(complex) +H_FIELD = (numpy.arange(3 * numpy.prod(SHAPE)).reshape((3, *SHAPE)) * 0.25 - 0.75j).astype(complex) + +PEC = numpy.zeros((3, *SHAPE), dtype=float) +PEC[1, 0, 1, 0] = 1.0 +PMC = numpy.zeros((3, *SHAPE), dtype=float) +PMC[2, 1, 2, 1] = 1.0 + +TF_REGION = numpy.zeros((3, *SHAPE), dtype=float) +TF_REGION[:, 0, 1, 0] = 1.0 + +BOUNDARY_SHAPE = (3, 4, 3) +BOUNDARY_DXES = [ + [numpy.array([1.0, 1.5, 0.8]), numpy.array([0.75, 1.25, 1.5, 0.9]), numpy.array([1.2, 0.8, 1.1])], + [numpy.array([0.9, 1.4, 1.0]), numpy.array([0.8, 1.1, 1.4, 1.0]), numpy.array([1.0, 0.7, 1.3])], +] +BOUNDARY_EPSILON = numpy.stack([ + numpy.linspace(1.0, 2.2, numpy.prod(BOUNDARY_SHAPE)).reshape(BOUNDARY_SHAPE), + numpy.linspace(1.1, 2.3, numpy.prod(BOUNDARY_SHAPE)).reshape(BOUNDARY_SHAPE), + numpy.linspace(1.2, 2.4, numpy.prod(BOUNDARY_SHAPE)).reshape(BOUNDARY_SHAPE), +]) +BOUNDARY_FIELD = (numpy.arange(3 * numpy.prod(BOUNDARY_SHAPE)).reshape((3, *BOUNDARY_SHAPE)) + 0.5j).astype(complex) + + +def apply_fdfd_matrix(op, field: numpy.ndarray, shape: tuple[int, ...] = SHAPE) -> numpy.ndarray: + return unvec(op @ vec(field), shape) diff --git a/meanas/test/_solver_cases.py b/meanas/test/_solver_cases.py new file mode 100644 index 0000000..364e1f0 --- /dev/null +++ b/meanas/test/_solver_cases.py @@ -0,0 +1,56 @@ +import dataclasses +import numpy +from scipy import sparse +import scipy.sparse.linalg as spalg + +from ._test_builders import unit_dxes + + +@dataclasses.dataclass(frozen=True) +class DiagonalEigenCase: + operator: sparse.csr_matrix + linear_operator: spalg.LinearOperator + guess_default: numpy.ndarray + guess_sparse: numpy.ndarray + + +@dataclasses.dataclass(frozen=True) +class SolverPlumbingCase: + omega: float + a0: sparse.csr_matrix + pl: sparse.csr_matrix + pr: sparse.csr_matrix + j: numpy.ndarray + guess: numpy.ndarray + solver_result: numpy.ndarray + dxes: tuple[tuple[numpy.ndarray, ...], tuple[numpy.ndarray, ...]] + epsilon: numpy.ndarray + + +def diagonal_eigen_case() -> DiagonalEigenCase: + operator = sparse.diags([5.0, 3.0, 1.0, -2.0]).tocsr() + linear_operator = spalg.LinearOperator( + shape=operator.shape, + dtype=complex, + matvec=lambda vv: operator @ vv, + ) + return DiagonalEigenCase( + operator=operator, + linear_operator=linear_operator, + guess_default=numpy.array([0.0, 1.0, 1e-6, 0.0], dtype=complex), + guess_sparse=numpy.array([1.0, 0.1, 0.0, 0.0], dtype=complex), + ) + + +def solver_plumbing_case() -> SolverPlumbingCase: + return SolverPlumbingCase( + omega=2.0, + a0=sparse.csr_matrix(numpy.array([[1.0 + 2.0j, 2.0], [3.0 - 1.0j, 4.0]])), + pl=sparse.csr_matrix(numpy.array([[2.0, 0.0], [0.0, 3.0j]])), + pr=sparse.csr_matrix(numpy.array([[0.5, 0.0], [0.0, -2.0j]])), + j=numpy.array([1.0 + 0.5j, -2.0]), + guess=numpy.array([0.25 - 0.75j, 1.5 + 0.5j]), + solver_result=numpy.array([3.0 - 1.0j, -4.0 + 2.0j]), + dxes=unit_dxes((1, 1, 1)), + epsilon=numpy.ones(2), + ) diff --git a/meanas/test/_test_builders.py b/meanas/test/_test_builders.py new file mode 100644 index 0000000..d8b2088 --- /dev/null +++ b/meanas/test/_test_builders.py @@ -0,0 +1,22 @@ +import numpy + + +def real_ramp(shape: tuple[int, ...], *, scale: float = 1.0, offset: float = 0.0) -> numpy.ndarray: + return numpy.arange(numpy.prod(shape), dtype=float).reshape(shape, order='C') * scale + offset + + +def complex_ramp( + shape: tuple[int, ...], + *, + scale: float = 1.0, + offset: float = 0.0, + imag_scale: float = 0.0, + imag_offset: float = 0.0, + ) -> numpy.ndarray: + real = real_ramp(shape, scale=scale, offset=offset) + imag = real_ramp(shape, scale=imag_scale, offset=imag_offset) + return (real + 1j * imag).astype(complex) + + +def unit_dxes(shape: tuple[int, ...]) -> tuple[tuple[numpy.ndarray, ...], tuple[numpy.ndarray, ...]]: + return tuple(tuple(numpy.ones(length) for length in shape) for _ in range(2)) # type: ignore[return-value] diff --git a/meanas/test/conftest.py b/meanas/test/conftest.py index 5dcdbff..5b577c6 100644 --- a/meanas/test/conftest.py +++ b/meanas/test/conftest.py @@ -3,12 +3,13 @@ Test fixtures """ -from typing import Iterable, Any +# ruff: noqa: ARG001 +from typing import Any import numpy from numpy.typing import NDArray import pytest # type: ignore -from .utils import PRNG +from .utils import make_prng FixtureRequest = Any @@ -20,18 +21,18 @@ FixtureRequest = Any (5, 5, 5), # (7, 7, 7), ]) -def shape(request: FixtureRequest) -> Iterable[tuple[int, ...]]: - yield (3, *request.param) +def shape(request: FixtureRequest) -> tuple[int, ...]: + return (3, *request.param) @pytest.fixture(scope='module', params=[1.0, 1.5]) -def epsilon_bg(request: FixtureRequest) -> Iterable[float]: - yield request.param +def epsilon_bg(request: FixtureRequest) -> float: + return request.param @pytest.fixture(scope='module', params=[1.0, 2.5]) -def epsilon_fg(request: FixtureRequest) -> Iterable[float]: - yield request.param +def epsilon_fg(request: FixtureRequest) -> float: + return request.param @pytest.fixture(scope='module', params=['center', '000', 'random']) @@ -40,7 +41,8 @@ def epsilon( shape: tuple[int, ...], epsilon_bg: float, epsilon_fg: float, - ) -> Iterable[NDArray[numpy.float64]]: + ) -> NDArray[numpy.float64]: + prng = make_prng() is3d = (numpy.array(shape) == 1).sum() == 0 if is3d: if request.param == '000': @@ -56,21 +58,23 @@ def epsilon( elif request.param == '000': epsilon[:, 0, 0, 0] = epsilon_fg elif request.param == 'random': - epsilon[:] = PRNG.uniform(low=min(epsilon_bg, epsilon_fg), - high=max(epsilon_bg, epsilon_fg), - size=shape) + epsilon[:] = prng.uniform( + low=min(epsilon_bg, epsilon_fg), + high=max(epsilon_bg, epsilon_fg), + size=shape, + ) - yield epsilon + return epsilon @pytest.fixture(scope='module', params=[1.0]) # 1.5 -def j_mag(request: FixtureRequest) -> Iterable[float]: - yield request.param +def j_mag(request: FixtureRequest) -> float: + return request.param @pytest.fixture(scope='module', params=[1.0, 1.5]) -def dx(request: FixtureRequest) -> Iterable[float]: - yield request.param +def dx(request: FixtureRequest) -> float: + return request.param @pytest.fixture(scope='module', params=['uniform', 'centerbig']) @@ -78,7 +82,8 @@ def dxes( request: FixtureRequest, shape: tuple[int, ...], dx: float, - ) -> Iterable[list[list[NDArray[numpy.float64]]]]: + ) -> list[list[NDArray[numpy.float64]]]: + prng = make_prng() if request.param == 'uniform': dxes = [[numpy.full(s, dx) for s in shape[1:]] for _ in range(2)] elif request.param == 'centerbig': @@ -87,8 +92,7 @@ def dxes( for ax in (0, 1, 2): dxes[eh][ax][dxes[eh][ax].size // 2] *= 1.1 elif request.param == 'random': - dxe = [PRNG.uniform(low=1.0 * dx, high=1.1 * dx, size=s) for s in shape[1:]] + dxe = [prng.uniform(low=1.0 * dx, high=1.1 * dx, size=s) for s in shape[1:]] dxh = [(d + numpy.roll(d, -1)) / 2 for d in dxe] dxes = [dxe, dxh] - yield dxes - + return dxes diff --git a/meanas/test/test_bloch_foundations.py b/meanas/test/test_bloch_foundations.py new file mode 100644 index 0000000..02a547c --- /dev/null +++ b/meanas/test/test_bloch_foundations.py @@ -0,0 +1,73 @@ +import numpy +from numpy.linalg import norm + +from ..fdfd import bloch +from ._bloch_case import EPSILON, G_MATRIX, H_MN, K0_AXIAL, K0_GENERAL, MU, SHAPE, ZERO_H_MN +from .utils import assert_close + +def test_generate_kmn_general_case_returns_orthonormal_basis() -> None: + k_mag, m_vecs, n_vecs = bloch.generate_kmn(K0_GENERAL, G_MATRIX, SHAPE) + + assert k_mag.shape == SHAPE + (1,) + assert m_vecs.shape == SHAPE + (3,) + assert n_vecs.shape == SHAPE + (3,) + assert numpy.isfinite(k_mag).all() + assert numpy.isfinite(m_vecs).all() + assert numpy.isfinite(n_vecs).all() + + assert_close(norm(m_vecs.reshape(-1, 3), axis=1), 1.0) + assert_close(norm(n_vecs.reshape(-1, 3), axis=1), 1.0) + assert_close(numpy.sum(m_vecs * n_vecs, axis=3), 0.0, atol=1e-12) + + +def test_generate_kmn_z_aligned_uses_default_transverse_basis() -> None: + k_mag, m_vecs, n_vecs = bloch.generate_kmn(K0_AXIAL, G_MATRIX, (1, 1, 1)) + + assert numpy.isfinite(k_mag).all() + assert_close(m_vecs[0, 0, 0], [0.0, 1.0, 0.0]) + assert_close(numpy.sum(m_vecs * n_vecs, axis=3), 0.0, atol=1e-12) + assert_close(norm(n_vecs.reshape(-1, 3), axis=1), 1.0) + + +def test_maxwell_operator_returns_finite_column_vector_without_mu() -> None: + operator = bloch.maxwell_operator(K0_GENERAL, G_MATRIX, EPSILON) + + result = operator(H_MN.copy()) + zero_result = operator(ZERO_H_MN.copy()) + + assert result.shape == (2 * numpy.prod(SHAPE), 1) + assert numpy.isfinite(result).all() + assert_close(zero_result, 0.0) + + +def test_maxwell_operator_returns_finite_column_vector_with_mu() -> None: + operator = bloch.maxwell_operator(K0_GENERAL, G_MATRIX, EPSILON, MU) + + result = operator(H_MN.copy()) + zero_result = operator(ZERO_H_MN.copy()) + + assert result.shape == (2 * numpy.prod(SHAPE), 1) + assert numpy.isfinite(result).all() + assert_close(zero_result, 0.0) + + +def test_inverse_maxwell_operator_returns_finite_column_vector_for_both_mu_branches() -> None: + for mu in (None, MU): + operator = bloch.inverse_maxwell_operator_approx(K0_GENERAL, G_MATRIX, EPSILON, mu) + + result = operator(H_MN.copy()) + zero_result = operator(ZERO_H_MN.copy()) + + assert result.shape == (2 * numpy.prod(SHAPE), 1) + assert numpy.isfinite(result).all() + assert_close(zero_result, 0.0) + + +def test_bloch_field_converters_return_finite_fields() -> None: + e_field = bloch.hmn_2_exyz(K0_GENERAL, G_MATRIX, EPSILON)(H_MN.copy()) + h_field = bloch.hmn_2_hxyz(K0_GENERAL, G_MATRIX, EPSILON)(H_MN.copy()) + + assert e_field.shape == (3, *SHAPE) + assert h_field.shape == (3, *SHAPE) + assert numpy.isfinite(e_field).all() + assert numpy.isfinite(h_field).all() diff --git a/meanas/test/test_bloch_interactions.py b/meanas/test/test_bloch_interactions.py new file mode 100644 index 0000000..0628a55 --- /dev/null +++ b/meanas/test/test_bloch_interactions.py @@ -0,0 +1,315 @@ +import numpy +import pytest +from numpy.testing import assert_allclose +from types import SimpleNamespace + +from ..fdfd import bloch +from ._bloch_case import EPSILON, G_MATRIX, H_SIZE, K0_X, Y0, Y0_TWO_MODE, build_overlap_fixture +from .utils import assert_close + + +def test_rtrace_atb_matches_real_frobenius_inner_product() -> None: + a_mat = numpy.array([[1.0 + 2.0j, 3.0 - 1.0j], [2.0j, 4.0]], dtype=complex) + b_mat = numpy.array([[5.0 - 1.0j, 1.0 + 1.0j], [2.0, 3.0j]], dtype=complex) + expected = numpy.real(numpy.sum(a_mat.conj() * b_mat)) + + assert bloch._rtrace_AtB(a_mat, b_mat) == expected + + +def test_symmetrize_returns_hermitian_average() -> None: + matrix = numpy.array([[1.0 + 2.0j, 3.0 - 1.0j], [2.0j, 4.0]], dtype=complex) + result = bloch._symmetrize(matrix) + + assert_close(result, 0.5 * (matrix + matrix.conj().T)) + assert_close(result, result.conj().T) + + +def test_inner_product_is_nonmutating_and_obeys_sign_symmetry() -> None: + e_in, h_in, e_out, h_out = build_overlap_fixture() + originals = (e_in.copy(), h_in.copy(), e_out.copy(), h_out.copy()) + + pp = bloch.inner_product(e_out, h_out, e_in, h_in) + pn = bloch.inner_product(e_out, h_out, e_in, -h_in) + np_term = bloch.inner_product(e_out, -h_out, e_in, h_in) + nn = bloch.inner_product(e_out, -h_out, e_in, -h_in) + + assert_close(pp, 0.8164965809277263 + 0.0j) + assert_close(pp, -nn, atol=1e-12, rtol=1e-12) + assert_close(pn, -np_term, atol=1e-12, rtol=1e-12) + assert numpy.array_equal(e_in, originals[0]) + assert numpy.array_equal(h_in, originals[1]) + assert numpy.array_equal(e_out, originals[2]) + assert numpy.array_equal(h_out, originals[3]) + + +def test_trq_returns_expected_transmission_and_reflection() -> None: + e_in, h_in, e_out, h_out = build_overlap_fixture() + + transmission, reflection = bloch.trq(e_in, h_in, e_out, h_out) + + assert_close(transmission, 0.9797958971132713 + 0.0j, atol=1e-12, rtol=1e-12) + assert_close(reflection, 0.2 + 0.0j, atol=1e-12, rtol=1e-12) + + +def test_eigsolve_returns_finite_modes_with_small_residual() -> None: + callback_count = 0 + + def callback() -> None: + nonlocal callback_count + callback_count += 1 + + eigvals, eigvecs = bloch.eigsolve( + 1, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=50, + y0=Y0, + callback=callback, + ) + + operator = bloch.maxwell_operator(K0_X, G_MATRIX, EPSILON) + eigvec = eigvecs[0] / numpy.linalg.norm(eigvecs[0]) + residual = numpy.linalg.norm(operator(eigvec).reshape(-1) - eigvals[0] * eigvec) / numpy.linalg.norm(eigvec) + + assert eigvals.shape == (1,) + assert eigvecs.shape == (1, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + assert residual < 1e-5 + assert callback_count > 0 + + +def test_eigsolve_without_initial_guess_returns_finite_modes() -> None: + eigvals, eigvecs = bloch.eigsolve( + 1, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=20, + y0=None, + ) + + operator = bloch.maxwell_operator(K0_X, G_MATRIX, EPSILON) + eigvec = eigvecs[0] / numpy.linalg.norm(eigvecs[0]) + residual = numpy.linalg.norm(operator(eigvec).reshape(-1) - eigvals[0] * eigvec) / numpy.linalg.norm(eigvec) + + assert eigvals.shape == (1,) + assert eigvecs.shape == (1, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + assert residual < 1e-5 + + +def test_eigsolve_recovers_from_singular_initial_subspace(monkeypatch: pytest.MonkeyPatch) -> None: + class FakeRng: + def __init__(self) -> None: + self.calls = 0 + + def random(self, shape: tuple[int, ...]) -> numpy.ndarray: + self.calls += 1 + return numpy.arange(numpy.prod(shape), dtype=float).reshape(shape) + self.calls + + fake_rng = FakeRng() + singular_y0 = numpy.vstack([Y0_TWO_MODE[0], Y0_TWO_MODE[0]]) + monkeypatch.setattr(bloch.numpy.random, 'default_rng', lambda: fake_rng) + + eigvals, eigvecs = bloch.eigsolve( + 2, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=20, + y0=singular_y0, + ) + + assert fake_rng.calls == 2 + assert eigvals.shape == (2,) + assert eigvecs.shape == (2, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + + +def test_eigsolve_reconditions_large_trace_initial_subspace(monkeypatch: pytest.MonkeyPatch) -> None: + original_inv = bloch.numpy.linalg.inv + original_sqrtm = bloch.scipy.linalg.sqrtm + sqrtm_calls = 0 + inv_calls = 0 + + def inv_with_large_first_trace(matrix: numpy.ndarray) -> numpy.ndarray: + nonlocal inv_calls + inv_calls += 1 + if inv_calls == 1: + return numpy.eye(matrix.shape[0], dtype=complex) * 1e9 + return original_inv(matrix) + + def sqrtm_wrapper(matrix: numpy.ndarray) -> numpy.ndarray: + nonlocal sqrtm_calls + sqrtm_calls += 1 + return original_sqrtm(matrix) + + monkeypatch.setattr(bloch.numpy.linalg, 'inv', inv_with_large_first_trace) + monkeypatch.setattr(bloch.scipy.linalg, 'sqrtm', sqrtm_wrapper) + + eigvals, eigvecs = bloch.eigsolve( + 2, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=20, + y0=Y0_TWO_MODE, + ) + + assert sqrtm_calls >= 2 + assert eigvals.shape == (2,) + assert eigvecs.shape == (2, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + + +def test_eigsolve_qi_memoization_reuses_cached_theta(monkeypatch: pytest.MonkeyPatch) -> None: + def fake_minimize_scalar(func, method: str, bounds: tuple[float, float], options: dict[str, float]) -> SimpleNamespace: + theta = 0.3 + first = func(theta) + second = func(theta) + assert_allclose(second, first) + return SimpleNamespace(fun=second, x=theta) + + monkeypatch.setattr(bloch.scipy.optimize, 'minimize_scalar', fake_minimize_scalar) + + eigvals, eigvecs = bloch.eigsolve( + 1, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=1, + y0=Y0, + ) + + assert eigvals.shape == (1,) + assert eigvecs.shape == (1, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + + +@pytest.mark.parametrize('theta', [numpy.pi / 2 - 1e-8, 1e-8]) +def test_eigsolve_qi_taylor_expansions_return_finite_modes(monkeypatch: pytest.MonkeyPatch, theta: float) -> None: + original_inv = bloch.numpy.linalg.inv + inv_calls = 0 + + def inv_raise_once_for_q(matrix: numpy.ndarray) -> numpy.ndarray: + nonlocal inv_calls + inv_calls += 1 + if inv_calls == 3: + raise numpy.linalg.LinAlgError('forced singular Q') + return original_inv(matrix) + + def fake_minimize_scalar(func, method: str, bounds: tuple[float, float], options: dict[str, float]) -> SimpleNamespace: + value = func(theta) + return SimpleNamespace(fun=value, x=theta) + + monkeypatch.setattr(bloch.numpy.linalg, 'inv', inv_raise_once_for_q) + monkeypatch.setattr(bloch.scipy.optimize, 'minimize_scalar', fake_minimize_scalar) + + eigvals, eigvecs = bloch.eigsolve( + 1, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=1, + y0=Y0, + ) + + assert eigvals.shape == (1,) + assert eigvecs.shape == (1, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + + +def test_eigsolve_qi_inexplicable_singularity_raises(monkeypatch: pytest.MonkeyPatch) -> None: + original_inv = bloch.numpy.linalg.inv + inv_calls = 0 + + def inv_raise_once_for_q(matrix: numpy.ndarray) -> numpy.ndarray: + nonlocal inv_calls + inv_calls += 1 + if inv_calls == 3: + raise numpy.linalg.LinAlgError('forced singular Q') + return original_inv(matrix) + + def fake_minimize_scalar(func, method: str, bounds: tuple[float, float], options: dict[str, float]) -> SimpleNamespace: + func(numpy.pi / 4) + raise AssertionError('unreachable after trace_func exception') + + monkeypatch.setattr(bloch.numpy.linalg, 'inv', inv_raise_once_for_q) + monkeypatch.setattr(bloch.scipy.optimize, 'minimize_scalar', fake_minimize_scalar) + + with pytest.raises(Exception, match='Inexplicable singularity in trace_func'): + bloch.eigsolve( + 1, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=1, + y0=Y0, + ) + + +def test_find_k_returns_vector_frequency_and_callbacks() -> None: + target_eigvals, _target_eigvecs = bloch.eigsolve( + 1, + K0_X, + G_MATRIX, + EPSILON, + tolerance=1e-6, + max_iters=50, + y0=Y0, + ) + target_frequency = float(numpy.sqrt(abs(numpy.real(target_eigvals[0])))) + + solve_calls = 0 + iter_calls = 0 + + def solve_callback(k_mag: float, eigvals: numpy.ndarray, eigvecs: numpy.ndarray, frequency: float) -> None: + nonlocal solve_calls + solve_calls += 1 + assert eigvals.shape == (1,) + assert eigvecs.shape == (1, H_SIZE) + assert isinstance(k_mag, float) + assert isinstance(frequency, float) + + def iter_callback() -> None: + nonlocal iter_calls + iter_calls += 1 + + found_k, found_frequency, eigvals, eigvecs = bloch.find_k( + target_frequency, + 1e-4, + [1, 0, 0], + G_MATRIX, + EPSILON, + band=0, + k_bounds=(0.05, 0.15), + v0=Y0, + solve_callback=solve_callback, + iter_callback=iter_callback, + ) + + assert found_k.shape == (3,) + assert numpy.isfinite(found_k).all() + assert_close(numpy.cross(found_k, [1.0, 0.0, 0.0]), 0.0, atol=1e-12, rtol=1e-12) + assert_close(found_k, K0_X, atol=1e-4, rtol=1e-4) + assert abs(found_frequency - target_frequency) <= 1e-4 + assert eigvals.shape == (1,) + assert eigvecs.shape == (1, H_SIZE) + assert numpy.isfinite(eigvals).all() + assert numpy.isfinite(eigvecs).all() + assert solve_calls > 0 + assert iter_calls > 0 diff --git a/meanas/test/test_eigensolvers_numerics.py b/meanas/test/test_eigensolvers_numerics.py new file mode 100644 index 0000000..cf037a6 --- /dev/null +++ b/meanas/test/test_eigensolvers_numerics.py @@ -0,0 +1,101 @@ +import numpy +from numpy.linalg import norm +import pytest + +from ._solver_cases import diagonal_eigen_case +from .utils import assert_close +from ..eigensolvers import power_iteration, rayleigh_quotient_iteration, signed_eigensolve + + +def test_rayleigh_quotient_iteration_with_linear_operator() -> None: + case = diagonal_eigen_case() + + def dense_solver( + shifted_operator, + rhs: numpy.ndarray, + ) -> numpy.ndarray: + basis = numpy.eye(case.operator.shape[0], dtype=complex) + columns = [shifted_operator.matvec(basis[:, ii]) for ii in range(case.operator.shape[0])] + dense_matrix = numpy.column_stack(columns) + return numpy.linalg.lstsq(dense_matrix, rhs, rcond=None)[0] + + eigval, eigvec = rayleigh_quotient_iteration( + case.linear_operator, + case.guess_default, + iterations=8, + solver=dense_solver, + ) + + residual = norm(case.operator @ eigvec - eigval * eigvec) + assert abs(eigval - 3.0) < 1e-12 + assert residual < 1e-12 + + +def test_signed_eigensolve_negative_returns_largest_negative_mode() -> None: + case = diagonal_eigen_case() + + eigvals, eigvecs = signed_eigensolve(case.operator, how_many=1, negative=True) + + assert eigvals.shape == (1,) + assert eigvecs.shape == (4, 1) + assert abs(eigvals[0] + 2.0) < 1e-12 + assert abs(eigvecs[3, 0]) > 0.99 + + +def test_rayleigh_quotient_iteration_uses_default_linear_operator_solver() -> None: + case = diagonal_eigen_case() + + eigval, eigvec = rayleigh_quotient_iteration( + case.linear_operator, + case.guess_default, + iterations=8, + ) + + residual = norm(case.operator @ eigvec - eigval * eigvec) + assert abs(eigval - 3.0) < 1e-12 + assert residual < 1e-12 + + +def test_signed_eigensolve_linear_operator_fallback_returns_dominant_positive_mode() -> None: + case = diagonal_eigen_case() + + eigvals, eigvecs = signed_eigensolve(case.linear_operator, how_many=1) + + assert eigvals.shape == (1,) + assert eigvecs.shape == (4, 1) + assert_close(eigvals[0], 5.0, atol=1e-12, rtol=1e-12) + assert abs(eigvecs[0, 0]) > 0.99 + + +def test_power_iteration_finds_dominant_mode() -> None: + case = diagonal_eigen_case() + eigval, eigvec = power_iteration(case.operator, guess_vector=numpy.ones(4, dtype=complex), iterations=20) + + assert eigval == pytest.approx(5.0, rel=1e-6) + assert abs(eigvec[0]) > abs(eigvec[1]) + + +def test_rayleigh_quotient_iteration_refines_known_sparse_mode() -> None: + case = diagonal_eigen_case() + + def solver(matrix, rhs: numpy.ndarray) -> numpy.ndarray: + return numpy.linalg.lstsq(matrix.toarray(), rhs, rcond=None)[0] + + eigval, eigvec = rayleigh_quotient_iteration( + case.operator, + case.guess_sparse, + iterations=8, + solver=solver, + ) + + residual = numpy.linalg.norm(case.operator @ eigvec - eigval * eigvec) + assert eigval == pytest.approx(3.0, rel=1e-6) + assert residual < 1e-8 + + +def test_signed_eigensolve_returns_largest_positive_modes() -> None: + case = diagonal_eigen_case() + eigvals, eigvecs = signed_eigensolve(case.operator, how_many=2) + + assert_close(eigvals, [3.0, 5.0], atol=1e-6) + assert eigvecs.shape == (4, 2) diff --git a/meanas/test/test_eme_numerics.py b/meanas/test/test_eme_numerics.py new file mode 100644 index 0000000..3237c1b --- /dev/null +++ b/meanas/test/test_eme_numerics.py @@ -0,0 +1,491 @@ +from typing import cast + +import numpy +import pytest +from scipy import sparse + +from ..fdmath import vec +from ..fdfd import eme, waveguide_2d, waveguide_cyl +from ._test_builders import complex_ramp, unit_dxes +from .utils import assert_close + + +SHAPE = (3, 2, 2) +DXES = unit_dxes((2, 2)) +WAVENUMBERS_L = numpy.array([1.0, 0.8]) +WAVENUMBERS_R = numpy.array([0.9, 0.7]) +OMEGA = 1 / 1500 +REAL_DXES = unit_dxes((5, 5)) + + +def _mode(scale: float) -> tuple[numpy.ndarray, numpy.ndarray]: + e_field = complex_ramp(SHAPE, offset=1.0 + scale) + h_field = complex_ramp(SHAPE, scale=0.2, offset=2.0, imag_offset=0.05 * scale) + return vec(e_field), vec(h_field) + + +def _mode_sets() -> tuple[list[tuple[numpy.ndarray, numpy.ndarray]], list[tuple[numpy.ndarray, numpy.ndarray]]]: + left_modes = [_mode(0.0), _mode(0.7)] + right_modes = [_mode(1.4), _mode(2.1)] + return left_modes, right_modes + + +def _gain_only_tr(*args, **kwargs) -> tuple[numpy.ndarray, numpy.ndarray]: + return numpy.array([[2.0, 0.0], [0.0, 0.5]]), numpy.zeros((2, 2)) + + +def _gain_and_reflection_tr(*args, **kwargs) -> tuple[numpy.ndarray, numpy.ndarray]: + return numpy.array([[2.0, 0.0], [0.0, 0.5]]), numpy.array([[0.0, 1.0], [2.0, 0.0]]) + + +def _nonsymmetric_tr(left_marker: object): + def fake_get_tr(_eh_left, wavenumbers_left, _eh_right, _wavenumbers_right, **kwargs): + if wavenumbers_left is left_marker: + return ( + numpy.array([[1.0, 2.0], [0.5, 1.0]]), + numpy.array([[0.0, 1.0], [2.0, 0.0]]), + ) + return ( + numpy.array([[1.0, -1.0], [0.0, 1.0]]), + numpy.array([[0.0, 0.5], [1.5, 0.0]]), + ) + + return fake_get_tr + + +def _dummy_modes() -> tuple[list[tuple[numpy.ndarray, numpy.ndarray]], numpy.ndarray]: + return [_mode(0.0), _mode(0.7)], numpy.array([1.0, 0.5]) + + +def test_get_tr_returns_finite_bounded_transfer_matrices() -> None: + left_modes, right_modes = _mode_sets() + + transmission, reflection = eme.get_tr( + left_modes, + WAVENUMBERS_L, + right_modes, + WAVENUMBERS_R, + dxes=DXES, + ) + + singular_values = numpy.linalg.svd(transmission, compute_uv=False) + + assert transmission.shape == (2, 2) + assert reflection.shape == (2, 2) + assert numpy.isfinite(transmission).all() + assert numpy.isfinite(reflection).all() + assert (singular_values <= 1.0 + 1e-12).all() + + +def test_get_abcd_matches_explicit_block_formula() -> None: + left_modes, right_modes = _mode_sets() + t12, r12 = eme.get_tr(left_modes, WAVENUMBERS_L, right_modes, WAVENUMBERS_R, dxes=DXES) + t21, r21 = eme.get_tr(right_modes, WAVENUMBERS_R, left_modes, WAVENUMBERS_L, dxes=DXES) + t21_inv = numpy.linalg.pinv(t21) + + expected = numpy.block([ + [t12 - r21 @ t21_inv @ r12, r21 @ t21_inv], + [-t21_inv @ r12, t21_inv], + ]) + abcd = eme.get_abcd(left_modes, WAVENUMBERS_L, right_modes, WAVENUMBERS_R, dxes=DXES) + + assert sparse.issparse(abcd) + assert abcd.shape == (4, 4) + assert_close(abcd.toarray(), expected) + + +def test_get_s_plain_matches_block_assembly_from_get_tr() -> None: + left_modes, right_modes = _mode_sets() + t12, r12 = eme.get_tr(left_modes, WAVENUMBERS_L, right_modes, WAVENUMBERS_R, dxes=DXES) + t21, r21 = eme.get_tr(right_modes, WAVENUMBERS_R, left_modes, WAVENUMBERS_L, dxes=DXES) + expected = numpy.block([[r12, t12], [t21, r21]]) + + ss = eme.get_s(left_modes, WAVENUMBERS_L, right_modes, WAVENUMBERS_R, dxes=DXES) + + assert ss.shape == (4, 4) + assert numpy.isfinite(ss).all() + assert_close(ss, expected) + + +def test_get_s_force_nogain_caps_singular_values(monkeypatch) -> None: + monkeypatch.setattr(eme, 'get_tr', _gain_only_tr) + modes, wavenumbers = _dummy_modes() + + plain_s = eme.get_s(modes, wavenumbers, modes, wavenumbers) + clipped_s = eme.get_s(modes, wavenumbers, modes, wavenumbers, force_nogain=True) + + plain_singular_values = numpy.linalg.svd(plain_s, compute_uv=False) + clipped_singular_values = numpy.linalg.svd(clipped_s, compute_uv=False) + + assert plain_singular_values.max() > 1.0 + assert (clipped_singular_values <= 1.0 + 1e-12).all() + assert numpy.isfinite(clipped_s).all() + + +def test_get_s_force_reciprocal_symmetrizes_output(monkeypatch) -> None: + left = numpy.array([1.0, 0.5]) + right = numpy.array([0.9, 0.4]) + modes, _wavenumbers = _dummy_modes() + + monkeypatch.setattr(eme, 'get_tr', _nonsymmetric_tr(left)) + ss = eme.get_s(modes, left, modes, right, force_reciprocal=True) + + assert_close(ss, ss.T) + + +def test_get_s_force_nogain_and_reciprocal_returns_finite_output(monkeypatch) -> None: + monkeypatch.setattr(eme, 'get_tr', _gain_and_reflection_tr) + modes, wavenumbers = _dummy_modes() + ss = eme.get_s(modes, wavenumbers, modes, wavenumbers, force_nogain=True, force_reciprocal=True) + + assert ss.shape == (4, 4) + assert numpy.isfinite(ss).all() + assert_close(ss, ss.T) + assert (numpy.linalg.svd(ss, compute_uv=False) <= 1.0 + 1e-12).all() + + +def test_get_tr_rejects_length_mismatches() -> None: + left_modes, right_modes = _mode_sets() + + with pytest.raises(ValueError, match='same length'): + eme.get_tr(left_modes[:1], WAVENUMBERS_L, right_modes, WAVENUMBERS_R, dxes=DXES) + + +def test_get_tr_rejects_malformed_mode_tuples() -> None: + bad_modes = cast(list[tuple[numpy.ndarray, numpy.ndarray]], [(numpy.ones(4, dtype=complex),)]) + + with pytest.raises(ValueError, match='2-tuple'): + eme.get_tr(bad_modes, [1.0], bad_modes, [1.0], dxes=DXES) + + +def test_get_tr_rejects_incompatible_field_shapes() -> None: + left_modes = [(numpy.ones(4, dtype=complex), numpy.ones(4, dtype=complex))] + right_modes = [(numpy.ones(6, dtype=complex), numpy.ones(6, dtype=complex))] + + with pytest.raises(ValueError, match='same E/H shapes'): + eme.get_tr(left_modes, [1.0], right_modes, [1.0], dxes=DXES) + + +def _build_real_epsilon() -> numpy.ndarray: + epsilon = numpy.ones((3, 5, 5), dtype=float) + epsilon[:, 2, 1] = 2.0 + return vec(epsilon) + + +def _build_straight_mode() -> tuple[tuple[numpy.ndarray, numpy.ndarray], complex, numpy.ndarray]: + epsilon = _build_real_epsilon() + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=REAL_DXES, + epsilon=epsilon, + ) + e_field, h_field = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=REAL_DXES, + epsilon=epsilon, + ) + return (e_field, h_field), wavenumber, epsilon + + +def _build_bend_mode() -> tuple[tuple[numpy.ndarray, numpy.ndarray], complex]: + epsilon = vec(numpy.ones((3, 5, 5), dtype=float)) + rmin = 10.0 + e_xy, angular_wavenumber = waveguide_cyl.solve_mode( + 0, + omega=OMEGA, + dxes=REAL_DXES, + epsilon=epsilon, + rmin=rmin, + ) + linear_wavenumber = waveguide_cyl.linear_wavenumbers( + [e_xy], + [angular_wavenumber], + epsilon=epsilon, + dxes=REAL_DXES, + rmin=rmin, + )[0] + e_field, h_field = waveguide_cyl.normalized_fields_e( + e_xy, + angular_wavenumber=angular_wavenumber, + omega=OMEGA, + dxes=REAL_DXES, + epsilon=epsilon, + rmin=rmin, + ) + return (e_field, h_field), linear_wavenumber + + +def _build_uniform_mode(index: float) -> tuple[tuple[numpy.ndarray, numpy.ndarray], complex]: + area = 25.0 + e_field = numpy.zeros((3, 5, 5), dtype=complex) + h_field = numpy.zeros((3, 5, 5), dtype=complex) + e_field[0] = numpy.sqrt(2.0 / (index * area)) + h_field[1] = numpy.sqrt(2.0 * index / area) + return (vec(e_field), vec(h_field)), complex(index * OMEGA) + + +def _interface_s(n_left: float, n_right: float) -> numpy.ndarray: + left_mode, left_beta = _build_uniform_mode(n_left) + right_mode, right_beta = _build_uniform_mode(n_right) + return eme.get_s([left_mode], [left_beta], [right_mode], [right_beta], dxes=REAL_DXES) + + +def _interface_abcd(n_left: float, n_right: float) -> numpy.ndarray: + left_mode, left_beta = _build_uniform_mode(n_left) + right_mode, right_beta = _build_uniform_mode(n_right) + return eme.get_abcd([left_mode], [left_beta], [right_mode], [right_beta], dxes=REAL_DXES).toarray() + + +def _expected_interface_s(n_left: float, n_right: float) -> numpy.ndarray: + reflection = (n_left - n_right) / (n_left + n_right) + transmission = 2 * numpy.sqrt(n_left * n_right) / (n_left + n_right) + return numpy.array( + [ + [reflection, transmission], + [transmission, -reflection], + ], + dtype=complex, + ) + + +def _propagation_abcd(beta: complex, length: float) -> numpy.ndarray: + phase = numpy.exp(-1j * beta * length) + return numpy.array( + [ + [phase, 0.0], + [0.0, phase ** -1], + ], + dtype=complex, + ) + + +def _abcd_to_s(abcd: numpy.ndarray) -> numpy.ndarray: + aa = abcd[0, 0] + bb = abcd[0, 1] + cc = abcd[1, 0] + dd = abcd[1, 1] + t21 = 1.0 / dd + r21 = bb / dd + r12 = -cc / dd + t12 = aa - bb * cc / dd + return numpy.array( + [ + [r12, t12], + [t21, r21], + ], + dtype=complex, + ) + + +def _expected_bragg_reflector_s(n_low: float, n_high: float, periods: int) -> numpy.ndarray: + ratio = n_high / n_low + reflection = (1 - ratio ** (2 * periods)) / (1 + ratio ** (2 * periods)) + transmission = ((-1) ** periods) * 2 * ratio ** periods / (1 + ratio ** (2 * periods)) + return numpy.array( + [ + [reflection, transmission], + [transmission, -reflection], + ], + dtype=complex, + ) + + +def test_get_s_is_near_identity_for_identical_solved_straight_modes() -> None: + mode, wavenumber, _epsilon = _build_straight_mode() + + ss = eme.get_s([mode], [wavenumber], [mode], [wavenumber], dxes=REAL_DXES) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert abs(ss[0, 0]) < 1e-6 + assert abs(ss[1, 1]) < 1e-6 + assert abs(abs(ss[0, 1]) - 1.0) < 1e-6 + assert abs(abs(ss[1, 0]) - 1.0) < 1e-6 + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 + + +def test_get_s_returns_finite_passive_output_for_small_straight_to_bend_fixture() -> None: + straight_mode, straight_wavenumber, _epsilon = _build_straight_mode() + bend_mode, bend_wavenumber = _build_bend_mode() + + ss = eme.get_s([straight_mode], [straight_wavenumber], [bend_mode], [bend_wavenumber], dxes=REAL_DXES) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 + + +def test_get_s_matches_analytic_fresnel_interface_for_uniform_one_mode_ports() -> None: + """ + For power-normalized one-mode ports at normal incidence, the interface matrix is + + r12 = (n_left - n_right) / (n_left + n_right) + r21 = -r12 + t12 = t21 = 2 * sqrt(n_left * n_right) / (n_left + n_right) + + so + + S = [[r12, t12], [t21, r21]]. + """ + ss = _interface_s(1.0, 2.0) + expected = _expected_interface_s(1.0, 2.0) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert_close(ss, expected, atol=1e-6, rtol=1e-6) + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 + + +def test_quarter_wave_matching_layer_is_nearly_reflectionless_at_design_frequency() -> None: + """ + A single quarter-wave matching layer with + + n1 = sqrt(n0 * n2), beta1 * L = pi / 2 + + cancels the two interface reflections at the design wavelength, so the + normal-incidence stack should satisfy `r = 0` and `|t| = 1`. + """ + n0 = 1.0 + n1 = numpy.sqrt(2.0) + n2 = 2.0 + interface_01 = _interface_abcd(n0, n1) + interface_12 = _interface_abcd(n1, n2) + _mode_1, beta_1 = _build_uniform_mode(float(n1)) + quarter_wave_length = numpy.pi / (2 * numpy.real(beta_1)) + + stack_abcd = interface_01 @ _propagation_abcd(beta_1, quarter_wave_length) @ interface_12 + ss = _abcd_to_s(stack_abcd) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert abs(ss[0, 0]) < 1e-12 + assert abs(ss[1, 1]) < 1e-12 + assert abs(abs(ss[0, 1]) - 1.0) < 1e-12 + assert abs(abs(ss[1, 0]) - 1.0) < 1e-12 + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 + + +def test_quarter_wave_ar_layer_reduces_reflection_relative_to_abrupt_interface() -> None: + """ + Compare the abrupt interface `n0 -> n2` against the quarter-wave matching-layer + stack `n0 -> sqrt(n0 n2) -> n2` at the same design wavelength. + + For the canonical `n0 = 1`, `n2 = 2` case, the abrupt interface has + + |r_abrupt| = |(n0 - n2) / (n0 + n2)| = 1 / 3, + + while the quarter-wave matching layer should cancel the interface reflections + so that `|r_ar|` is essentially zero and `|t_ar|` is correspondingly larger. + """ + n0 = 1.0 + n2 = 2.0 + abrupt = _interface_s(n0, n2) + + n1 = numpy.sqrt(n0 * n2) + interface_01 = _interface_abcd(n0, n1) + interface_12 = _interface_abcd(n1, n2) + _mode_1, beta_1 = _build_uniform_mode(float(n1)) + quarter_wave_length = numpy.pi / (2 * numpy.real(beta_1)) + ar_stack = _abcd_to_s(interface_01 @ _propagation_abcd(beta_1, quarter_wave_length) @ interface_12) + + abrupt_reflection = abs(abrupt[0, 0]) + abrupt_transmission = abs(abrupt[1, 0]) + ar_reflection = abs(ar_stack[0, 0]) + ar_transmission = abs(ar_stack[1, 0]) + + assert numpy.linalg.svd(abrupt, compute_uv=False).max() <= 1.0 + 1e-10 + assert numpy.linalg.svd(ar_stack, compute_uv=False).max() <= 1.0 + 1e-10 + assert ar_reflection < abrupt_reflection + assert ar_transmission > abrupt_transmission + assert ar_reflection < 1e-12 + assert abs(abrupt_reflection - (1.0 / 3.0)) < 1e-12 + + +def test_half_wave_uniform_slab_restores_unit_transmission_between_matched_media() -> None: + """ + For matched exterior media `n0 = n2`, a half-wave slab with + + beta1 * L = pi + + contributes only a global phase, so the stack returns to `r = 0` and + `|t| = 1` at the design wavelength. + """ + n0 = 1.0 + n1 = 2.0 + interface_01 = _interface_abcd(n0, n1) + interface_10 = _interface_abcd(n1, n0) + _mode_1, beta_1 = _build_uniform_mode(n1) + half_wave_length = numpy.pi / numpy.real(beta_1) + + stack_abcd = interface_01 @ _propagation_abcd(beta_1, half_wave_length) @ interface_10 + ss = _abcd_to_s(stack_abcd) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert abs(ss[0, 0]) < 1e-12 + assert abs(ss[1, 1]) < 1e-12 + assert abs(abs(ss[0, 1]) - 1.0) < 1e-12 + assert abs(abs(ss[1, 0]) - 1.0) < 1e-12 + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 + + +def test_strong_uniform_index_mismatch_behaves_like_near_termination() -> None: + """ + In the large-index-ratio limit, the same Fresnel formulas approach a hard-wall + reflector: + + |r| -> 1, |t| -> 0 as n_right / n_left -> infinity. + """ + ss = _interface_s(1.0, 100.0) + expected = _expected_interface_s(1.0, 100.0) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert_close(ss, expected, atol=1e-6, rtol=1e-6) + assert abs(ss[0, 0]) > 0.9 + assert abs(ss[1, 0]) < 0.25 + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 + + +def test_quarter_wave_bragg_reflector_matches_closed_form_stopband_response() -> None: + """ + For `N` quarter-wave high/low periods at the Bragg wavelength with identical + low-index incident and exit media (`n0 = ns = n_low`), + + M_pair = diag(-(n_low / n_high), -(n_high / n_low)) + M_stack = M_pair ** N + + which yields the closed-form scattering amplitudes + + r = (1 - (n_high / n_low) ** (2N)) / (1 + (n_high / n_low) ** (2N)) + t = 2 * (n_high / n_low) ** N / (1 + (n_high / n_low) ** (2N)). + + The reflector should therefore sit deep in the stopband with `|r|` near 1 and + `|t|` correspondingly small. + """ + n_low = 1.0 + n_high = 2.0 + periods = 5 + interface_lh = _interface_abcd(n_low, n_high) + interface_hl = _interface_abcd(n_high, n_low) + _mode_h, beta_h = _build_uniform_mode(n_high) + _mode_l, beta_l = _build_uniform_mode(n_low) + quarter_wave_high = numpy.pi / (2 * numpy.real(beta_h)) + quarter_wave_low = numpy.pi / (2 * numpy.real(beta_l)) + + stack_abcd = numpy.eye(2, dtype=complex) + for _ in range(periods): + stack_abcd = stack_abcd @ interface_lh @ _propagation_abcd(beta_h, quarter_wave_high) + stack_abcd = stack_abcd @ interface_hl @ _propagation_abcd(beta_l, quarter_wave_low) + ss = _abcd_to_s(stack_abcd) + expected = _expected_bragg_reflector_s(n_low, n_high, periods) + + assert ss.shape == (2, 2) + assert numpy.isfinite(ss).all() + assert_close(ss, expected, atol=1e-12, rtol=1e-12) + assert abs(ss[0, 0]) > 0.99 + assert abs(ss[1, 0]) < 0.1 + assert numpy.linalg.svd(ss, compute_uv=False).max() <= 1.0 + 1e-10 diff --git a/meanas/test/test_examples_smoke.py b/meanas/test/test_examples_smoke.py new file mode 100644 index 0000000..b21f90b --- /dev/null +++ b/meanas/test/test_examples_smoke.py @@ -0,0 +1,47 @@ +from pathlib import Path +import os +import subprocess +import sys + +import pytest + + +pytestmark = pytest.mark.complete + +REPO_ROOT = Path(__file__).resolve().parents[2] + + +def _run_example(example_name: str, tmp_path: Path) -> subprocess.CompletedProcess[str]: + env = os.environ.copy() + env['MPLBACKEND'] = 'Agg' + env['MPLCONFIGDIR'] = str(tmp_path / f'mpl-{example_name}') + return subprocess.run( + [sys.executable, str(REPO_ROOT / 'examples' / example_name)], + cwd=REPO_ROOT, + env=env, + text=True, + capture_output=True, + check=False, + timeout=60, + ) + + +def test_eme_example_smoke_runs(tmp_path: Path) -> None: + pytest.importorskip('matplotlib') + + result = _run_example('eme.py', tmp_path) + + assert result.returncode == 0, result.stdout + result.stderr + assert 'left effective indices:' in result.stdout + assert 'fundamental left-to-right transmission' in result.stdout + + +def test_eme_bend_example_smoke_runs(tmp_path: Path) -> None: + pytest.importorskip('matplotlib') + pytest.importorskip('skrf') + + result = _run_example('eme_bend.py', tmp_path) + + assert result.returncode == 0, result.stdout + result.stderr + assert 'straight effective indices:' in result.stdout + assert 'cascaded bend through power' in result.stdout diff --git a/meanas/test/test_fdfd.py b/meanas/test/test_fdfd.py index 009c65b..82587b4 100644 --- a/meanas/test/test_fdfd.py +++ b/meanas/test/test_fdfd.py @@ -1,4 +1,4 @@ -from typing import Iterable +# ruff: noqa: ARG001 import dataclasses import pytest # type: ignore import numpy @@ -6,7 +6,7 @@ from numpy.typing import NDArray #from numpy.testing import assert_allclose, assert_array_equal from .. import fdfd -from ..fdmath import vec, unvec +from ..fdmath import vec, unvec, vcfdfield, vfdfield, dx_lists_t from .utils import assert_close # , assert_fields_close from .conftest import FixtureRequest @@ -61,24 +61,24 @@ def test_poynting_planes(sim: 'FDResult') -> None: # Also see conftest.py @pytest.fixture(params=[1 / 1500]) -def omega(request: FixtureRequest) -> Iterable[float]: - yield request.param +def omega(request: FixtureRequest) -> float: + return request.param @pytest.fixture(params=[None]) -def pec(request: FixtureRequest) -> Iterable[NDArray[numpy.float64] | None]: - yield request.param +def pec(request: FixtureRequest) -> NDArray[numpy.float64] | None: + return request.param @pytest.fixture(params=[None]) -def pmc(request: FixtureRequest) -> Iterable[NDArray[numpy.float64] | None]: - yield request.param +def pmc(request: FixtureRequest) -> NDArray[numpy.float64] | None: + return request.param #@pytest.fixture(scope='module', # params=[(25, 5, 5)]) -#def shape(request): -# yield (3, *request.param) +#def shape(request: FixtureRequest): +# return (3, *request.param) @pytest.fixture(params=['diag']) # 'center' @@ -86,7 +86,7 @@ def j_distribution( request: FixtureRequest, shape: tuple[int, ...], j_mag: float, - ) -> Iterable[NDArray[numpy.float64]]: + ) -> NDArray[numpy.float64]: j = numpy.zeros(shape, dtype=complex) center_mask = numpy.zeros(shape, dtype=bool) center_mask[:, shape[1] // 2, shape[2] // 2, shape[3] // 2] = True @@ -96,22 +96,22 @@ def j_distribution( elif request.param == 'diag': j[numpy.roll(center_mask, [1, 1, 1], axis=(1, 2, 3))] = (1 + 1j) * j_mag j[numpy.roll(center_mask, [-1, -1, -1], axis=(1, 2, 3))] = (1 - 1j) * j_mag - yield j + return j @dataclasses.dataclass() class FDResult: shape: tuple[int, ...] - dxes: list[list[NDArray[numpy.float64]]] - epsilon: NDArray[numpy.float64] + dxes: dx_lists_t + epsilon: vfdfield omega: complex - j: NDArray[numpy.complex128] - e: NDArray[numpy.complex128] - pmc: NDArray[numpy.float64] | None - pec: NDArray[numpy.float64] | None + j: vcfdfield + e: vcfdfield + pmc: vfdfield | None + pec: vfdfield | None -@pytest.fixture() +@pytest.fixture def sim( request: FixtureRequest, shape: tuple[int, ...], @@ -141,11 +141,11 @@ def sim( j_vec = vec(j_distribution) eps_vec = vec(epsilon) e_vec = fdfd.solvers.generic( - J=j_vec, - omega=omega, - dxes=dxes, - epsilon=eps_vec, - matrix_solver_opts={'atol': 1e-15, 'tol': 1e-11}, + J = j_vec, + omega = omega, + dxes = dxes, + epsilon = eps_vec, + matrix_solver_opts = dict(atol=1e-15, rtol=1e-11), ) e = unvec(e_vec, shape[1:]) diff --git a/meanas/test/test_fdfd_algebra_helpers.py b/meanas/test/test_fdfd_algebra_helpers.py new file mode 100644 index 0000000..825edb3 --- /dev/null +++ b/meanas/test/test_fdfd_algebra_helpers.py @@ -0,0 +1,213 @@ +import numpy + +from ..fdmath import vec, unvec +from ..fdmath import functional as fd_functional +from ..fdfd import operators, scpml +from ._fdfd_case import ( + BOUNDARY_DXES, + BOUNDARY_EPSILON, + BOUNDARY_FIELD, + BOUNDARY_SHAPE, + DXES, + EPSILON, + E_FIELD, + MU, + H_FIELD, + OMEGA, + PEC, + PMC, + SHAPE, + apply_fdfd_matrix, +) +from .utils import assert_close, assert_fields_close + + +def _dense_e_full(mu: numpy.ndarray | None) -> numpy.ndarray: + ce = fd_functional.curl_forward(DXES[0]) + ch = fd_functional.curl_back(DXES[1]) + pe = numpy.where(PEC, 0.0, 1.0) + pm = numpy.where(PMC, 0.0, 1.0) + + masked_e = pe * E_FIELD + curl_term = ce(masked_e) + if mu is not None: + curl_term = curl_term / mu + curl_term = pm * curl_term + curl_term = ch(curl_term) + return pe * (curl_term - OMEGA**2 * EPSILON * masked_e) + + +def _dense_h_full(mu: numpy.ndarray | None) -> numpy.ndarray: + ce = fd_functional.curl_forward(DXES[0]) + ch = fd_functional.curl_back(DXES[1]) + pe = numpy.where(PEC, 0.0, 1.0) + pm = numpy.where(PMC, 0.0, 1.0) + magnetic = numpy.ones_like(EPSILON) if mu is None else mu + + masked_h = pm * H_FIELD + curl_term = ch(masked_h) + curl_term = pe * (curl_term / EPSILON) + curl_term = ce(curl_term) + return pm * (curl_term - OMEGA**2 * magnetic * masked_h) + + +def _normalized_distance(u: numpy.ndarray, size: int, thickness: int) -> numpy.ndarray: + return ((thickness - u).clip(0) + (u - (size - thickness)).clip(0)) / thickness + + +def test_h_full_matches_dense_reference_with_and_without_mu() -> None: + for mu in (None, MU): + matrix_result = apply_fdfd_matrix( + operators.h_full(OMEGA, DXES, vec(EPSILON), None if mu is None else vec(mu), vec(PEC), vec(PMC)), + H_FIELD, + ) + dense_result = _dense_h_full(mu) + assert_fields_close(matrix_result, dense_result, atol=1e-10, rtol=1e-10) + + +def test_e_full_matches_dense_reference_with_masks() -> None: + for mu in (None, MU): + matrix_result = apply_fdfd_matrix( + operators.e_full(OMEGA, DXES, vec(EPSILON), None if mu is None else vec(mu), vec(PEC), vec(PMC)), + E_FIELD, + ) + dense_result = _dense_e_full(mu) + assert_fields_close(matrix_result, dense_result, atol=1e-10, rtol=1e-10) + + +def test_h_full_without_masks_matches_dense_reference() -> None: + ce = fd_functional.curl_forward(DXES[0]) + ch = fd_functional.curl_back(DXES[1]) + dense_result = ce(ch(H_FIELD) / EPSILON) - OMEGA**2 * MU * H_FIELD + matrix_result = apply_fdfd_matrix( + operators.h_full(OMEGA, DXES, vec(EPSILON), vec(MU)), + H_FIELD, + ) + assert_fields_close(matrix_result, dense_result, atol=1e-10, rtol=1e-10) + + +def test_eh_full_matches_manual_block_operator_with_masks() -> None: + pe = numpy.where(PEC, 0.0, 1.0) + pm = numpy.where(PMC, 0.0, 1.0) + ce = fd_functional.curl_forward(DXES[0]) + ch = fd_functional.curl_back(DXES[1]) + + matrix_result = operators.eh_full(OMEGA, DXES, vec(EPSILON), vec(MU), vec(PEC), vec(PMC)) @ numpy.concatenate( + [vec(E_FIELD), vec(H_FIELD)], + ) + matrix_e, matrix_h = (unvec(part, SHAPE) for part in numpy.split(matrix_result, 2)) + + dense_e = pe * ch(pm * H_FIELD) - pe * (1j * OMEGA * EPSILON * (pe * E_FIELD)) + dense_h = pm * ce(pe * E_FIELD) + pm * (1j * OMEGA * MU * (pm * H_FIELD)) + + assert_fields_close(matrix_e, dense_e, atol=1e-10, rtol=1e-10) + assert_fields_close(matrix_h, dense_h, atol=1e-10, rtol=1e-10) + + +def test_e2h_pmc_mask_matches_masked_unmasked_result() -> None: + pmc_complement = numpy.where(PMC, 0.0, 1.0) + unmasked = apply_fdfd_matrix(operators.e2h(OMEGA, DXES, vec(MU)), E_FIELD) + masked = apply_fdfd_matrix(operators.e2h(OMEGA, DXES, vec(MU), vec(PMC)), E_FIELD) + + assert_fields_close(masked, pmc_complement * unmasked, atol=1e-10, rtol=1e-10) + + +def test_poynting_h_cross_matches_negative_e_cross_relation() -> None: + h_cross_e = apply_fdfd_matrix(operators.poynting_h_cross(vec(H_FIELD), DXES), E_FIELD) + e_cross_h = apply_fdfd_matrix(operators.poynting_e_cross(vec(E_FIELD), DXES), H_FIELD) + + assert_fields_close(h_cross_e, -e_cross_h, atol=1e-10, rtol=1e-10) + + +def test_e_boundary_source_interior_mask_is_independent_of_periodic_edges() -> None: + mask = numpy.zeros((3, *BOUNDARY_SHAPE), dtype=float) + mask[:, 1, 1, 1] = 1.0 + + periodic = operators.e_boundary_source(vec(mask), OMEGA, BOUNDARY_DXES, vec(BOUNDARY_EPSILON), periodic_mask_edges=True) + mirrored = operators.e_boundary_source(vec(mask), OMEGA, BOUNDARY_DXES, vec(BOUNDARY_EPSILON), periodic_mask_edges=False) + + assert_close(periodic.toarray(), mirrored.toarray()) + + +def test_e_boundary_source_periodic_edges_add_opposite_face_response() -> None: + mask = numpy.zeros((3, *BOUNDARY_SHAPE), dtype=float) + mask[:, 0, 1, 1] = 1.0 + + periodic = operators.e_boundary_source(vec(mask), OMEGA, BOUNDARY_DXES, vec(BOUNDARY_EPSILON), periodic_mask_edges=True) + mirrored = operators.e_boundary_source(vec(mask), OMEGA, BOUNDARY_DXES, vec(BOUNDARY_EPSILON), periodic_mask_edges=False) + diff = unvec((periodic - mirrored) @ vec(BOUNDARY_FIELD), BOUNDARY_SHAPE) + + assert numpy.isfinite(diff).all() + assert_close(diff[:, 1:-1, :, :], 0.0) + assert numpy.linalg.norm(diff[:, -1, :, :]) > 0 + + +def test_prepare_s_function_matches_closed_form_polynomial() -> None: + ln_r = -12.0 + order = 3.0 + distances = numpy.array([0.0, 0.25, 0.5, 1.0]) + s_function = scpml.prepare_s_function(ln_R=ln_r, m=order) + expected = (order + 1) * ln_r / 2 * distances**order + + assert_close(s_function(distances), expected) + + +def test_uniform_grid_scpml_matches_expected_stretch_profile() -> None: + s_function = scpml.prepare_s_function(ln_R=-12.0, m=3.0) + dxes = scpml.uniform_grid_scpml((6, 4, 3), (2, 0, 1), omega=2.0, epsilon_effective=4.0, s_function=s_function) + correction = numpy.sqrt(4.0) * 2.0 + + for axis, size, thickness in ((0, 6, 2), (2, 3, 1)): + grid = numpy.arange(size, dtype=float) + expected_a = 1 + 1j * s_function(_normalized_distance(grid, size, thickness)) / correction + expected_b = 1 + 1j * s_function(_normalized_distance(grid + 0.5, size, thickness)) / correction + assert_close(dxes[0][axis], expected_a) + assert_close(dxes[1][axis], expected_b) + + assert_close(dxes[0][1], 1.0) + assert_close(dxes[1][1], 1.0) + assert numpy.isfinite(dxes[0][0]).all() + assert numpy.isfinite(dxes[1][0]).all() + + +def test_uniform_grid_scpml_default_s_function_matches_explicit_default() -> None: + implicit = scpml.uniform_grid_scpml((6, 4, 3), (2, 0, 1), omega=2.0) + explicit = scpml.uniform_grid_scpml((6, 4, 3), (2, 0, 1), omega=2.0, s_function=scpml.prepare_s_function()) + + for implicit_group, explicit_group in zip(implicit, explicit, strict=True): + for implicit_axis, explicit_axis in zip(implicit_group, explicit_group, strict=True): + assert_close(implicit_axis, explicit_axis) + + +def test_stretch_with_scpml_only_modifies_requested_front_edge() -> None: + s_function = scpml.prepare_s_function(ln_R=-12.0, m=3.0) + base = [[numpy.ones(6), numpy.ones(4), numpy.ones(3)] for _ in range(2)] + stretched = scpml.stretch_with_scpml(base, axis=0, polarity=1, omega=2.0, epsilon_effective=4.0, thickness=2, s_function=s_function) + + assert_close(stretched[0][0][2:], 1.0) + assert_close(stretched[1][0][2:], 1.0) + assert_close(stretched[0][0][-2:], 1.0) + assert_close(stretched[1][0][-2:], 1.0) + assert numpy.linalg.norm(stretched[0][0][:2] - 1.0) > 0 + assert numpy.linalg.norm(stretched[1][0][:2] - 1.0) > 0 + + +def test_stretch_with_scpml_only_modifies_requested_back_edge() -> None: + s_function = scpml.prepare_s_function(ln_R=-12.0, m=3.0) + base = [[numpy.ones(6), numpy.ones(4), numpy.ones(3)] for _ in range(2)] + stretched = scpml.stretch_with_scpml(base, axis=0, polarity=-1, omega=2.0, epsilon_effective=4.0, thickness=2, s_function=s_function) + + assert_close(stretched[0][0][:4], 1.0) + assert_close(stretched[1][0][:4], 1.0) + assert numpy.linalg.norm(stretched[0][0][-2:] - 1.0) > 0 + assert numpy.linalg.norm(stretched[1][0][-2:] - 1.0) > 0 + + +def test_stretch_with_scpml_thickness_zero_is_noop() -> None: + s_function = scpml.prepare_s_function(ln_R=-12.0, m=3.0) + base = [[numpy.ones(6), numpy.ones(4), numpy.ones(3)] for _ in range(2)] + stretched = scpml.stretch_with_scpml(base, axis=0, polarity=-1, omega=2.0, epsilon_effective=4.0, thickness=0, s_function=s_function) + + for grid_group in stretched: + for axis_grid in grid_group: + assert_close(axis_grid, 1.0) diff --git a/meanas/test/test_fdfd_farfield.py b/meanas/test/test_fdfd_farfield.py new file mode 100644 index 0000000..5e2daab --- /dev/null +++ b/meanas/test/test_fdfd_farfield.py @@ -0,0 +1,100 @@ +import numpy +import pytest + +from ..fdfd import farfield + + +NEAR_SHAPE = (2, 3) +E_NEAR = [numpy.zeros(NEAR_SHAPE, dtype=complex), numpy.zeros(NEAR_SHAPE, dtype=complex)] +H_NEAR = [numpy.zeros(NEAR_SHAPE, dtype=complex), numpy.zeros(NEAR_SHAPE, dtype=complex)] + + +def test_near_to_farfield_rejects_wrong_length_inputs() -> None: + with pytest.raises(Exception, match='E_near must be a length-2 list'): + farfield.near_to_farfield(E_NEAR[:1], H_NEAR, dx=0.2, dy=0.3) + + with pytest.raises(Exception, match='H_near must be a length-2 list'): + farfield.near_to_farfield(E_NEAR, H_NEAR[:1], dx=0.2, dy=0.3) + + +def test_near_to_farfield_rejects_mismatched_shapes() -> None: + bad_h_near = [H_NEAR[0], numpy.zeros((2, 4), dtype=complex)] + + with pytest.raises(Exception, match='All fields must be the same shape'): + farfield.near_to_farfield(E_NEAR, bad_h_near, dx=0.2, dy=0.3) + + +def test_near_to_farfield_uses_default_and_scalar_padding_shapes() -> None: + default_result = farfield.near_to_farfield(E_NEAR, H_NEAR, dx=0.2, dy=0.3) + scalar_result = farfield.near_to_farfield(E_NEAR, H_NEAR, dx=0.2, dy=0.3, padded_size=8) + + assert default_result['E'][0].shape == (2, 4) + assert default_result['H'][0].shape == (2, 4) + assert scalar_result['E'][0].shape == (8, 8) + assert scalar_result['H'][0].shape == (8, 8) + + +def test_far_to_nearfield_rejects_wrong_length_inputs() -> None: + ff = farfield.near_to_farfield(E_NEAR, H_NEAR, dx=0.2, dy=0.3, padded_size=8) + + with pytest.raises(Exception, match='E_far must be a length-2 list'): + farfield.far_to_nearfield(ff['E'][:1], ff['H'], ff['dkx'], ff['dky']) + + with pytest.raises(Exception, match='H_far must be a length-2 list'): + farfield.far_to_nearfield(ff['E'], ff['H'][:1], ff['dkx'], ff['dky']) + + +def test_far_to_nearfield_rejects_mismatched_shapes() -> None: + ff = farfield.near_to_farfield(E_NEAR, H_NEAR, dx=0.2, dy=0.3, padded_size=8) + bad_h_far = [ff['H'][0], numpy.zeros((8, 4), dtype=complex)] + + with pytest.raises(Exception, match='All fields must be the same shape'): + farfield.far_to_nearfield(ff['E'], bad_h_far, ff['dkx'], ff['dky']) + + +def test_far_to_nearfield_uses_default_and_scalar_padding_shapes() -> None: + ff = farfield.near_to_farfield(E_NEAR, H_NEAR, dx=0.2, dy=0.3, padded_size=8) + default_result = farfield.far_to_nearfield( + [field.copy() for field in ff['E']], + [field.copy() for field in ff['H']], + ff['dkx'], + ff['dky'], + ) + scalar_result = farfield.far_to_nearfield( + [field.copy() for field in ff['E']], + [field.copy() for field in ff['H']], + ff['dkx'], + ff['dky'], + padded_size=4, + ) + + assert default_result['E'][0].shape == (8, 8) + assert default_result['H'][0].shape == (8, 8) + assert scalar_result['E'][0].shape == (4, 4) + assert scalar_result['H'][0].shape == (4, 4) + + +def test_farfield_roundtrip_supports_rectangular_arrays() -> None: + e_near = [numpy.zeros((4, 8), dtype=complex), numpy.zeros((4, 8), dtype=complex)] + h_near = [numpy.zeros((4, 8), dtype=complex), numpy.zeros((4, 8), dtype=complex)] + e_near[0][1, 3] = 1.0 + 0.25j + h_near[1][2, 5] = -0.5j + + ff = farfield.near_to_farfield(e_near, h_near, dx=0.2, dy=0.3, padded_size=(4, 8)) + restored = farfield.far_to_nearfield( + [field.copy() for field in ff['E']], + [field.copy() for field in ff['H']], + ff['dkx'], + ff['dky'], + padded_size=(4, 8), + ) + + assert isinstance(ff['dkx'], float) + assert isinstance(ff['dky'], float) + assert ff['E'][0].shape == (4, 8) + assert restored['E'][0].shape == (4, 8) + assert restored['H'][0].shape == (4, 8) + assert restored['dx'] == pytest.approx(0.2) + assert restored['dy'] == pytest.approx(0.3) + assert numpy.isfinite(restored['E'][0]).all() + assert numpy.isfinite(restored['H'][0]).all() diff --git a/meanas/test/test_fdfd_functional.py b/meanas/test/test_fdfd_functional.py new file mode 100644 index 0000000..9c1f771 --- /dev/null +++ b/meanas/test/test_fdfd_functional.py @@ -0,0 +1,122 @@ +import numpy + +from ..fdmath import unvec, vec +from ..fdfd import functional, operators +from ._fdfd_case import DXES, EPSILON, E_FIELD, H_FIELD, MU, OMEGA, SHAPE, TF_REGION, apply_fdfd_matrix +from .utils import assert_fields_close + + +ATOL = 1e-9 +RTOL = 1e-9 + + +def assert_fields_match(actual: numpy.ndarray, expected: numpy.ndarray) -> None: + assert_fields_close(actual, expected, atol=ATOL, rtol=RTOL) + + +def test_e_full_matches_sparse_operator_without_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.e_full(OMEGA, DXES, vec(EPSILON)), + E_FIELD, + ) + functional_result = functional.e_full(OMEGA, DXES, EPSILON)(E_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_e_full_matches_sparse_operator_with_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.e_full(OMEGA, DXES, vec(EPSILON), vec(MU)), + E_FIELD, + ) + functional_result = functional.e_full(OMEGA, DXES, EPSILON, MU)(E_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_eh_full_matches_sparse_operator_with_mu() -> None: + matrix_result = operators.eh_full(OMEGA, DXES, vec(EPSILON), vec(MU)) @ numpy.concatenate([vec(E_FIELD), vec(H_FIELD)]) + matrix_e, matrix_h = (unvec(part, SHAPE) for part in numpy.split(matrix_result, 2)) + functional_e, functional_h = functional.eh_full(OMEGA, DXES, EPSILON, MU)(E_FIELD, H_FIELD) + + assert_fields_match(functional_e, matrix_e) + assert_fields_match(functional_h, matrix_h) + + +def test_eh_full_matches_sparse_operator_without_mu() -> None: + matrix_result = operators.eh_full(OMEGA, DXES, vec(EPSILON)) @ numpy.concatenate([vec(E_FIELD), vec(H_FIELD)]) + matrix_e, matrix_h = (unvec(part, SHAPE) for part in numpy.split(matrix_result, 2)) + functional_e, functional_h = functional.eh_full(OMEGA, DXES, EPSILON)(E_FIELD, H_FIELD) + + assert_fields_match(functional_e, matrix_e) + assert_fields_match(functional_h, matrix_h) + + +def test_e2h_matches_sparse_operator_with_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.e2h(OMEGA, DXES, vec(MU)), + E_FIELD, + ) + functional_result = functional.e2h(OMEGA, DXES, MU)(E_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_e2h_matches_sparse_operator_without_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.e2h(OMEGA, DXES), + E_FIELD, + ) + functional_result = functional.e2h(OMEGA, DXES)(E_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_m2j_matches_sparse_operator_without_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.m2j(OMEGA, DXES), + H_FIELD, + ) + functional_result = functional.m2j(OMEGA, DXES)(H_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_m2j_matches_sparse_operator_with_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.m2j(OMEGA, DXES, vec(MU)), + H_FIELD, + ) + functional_result = functional.m2j(OMEGA, DXES, MU)(H_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_e_tfsf_source_matches_sparse_operator_without_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.e_tfsf_source(vec(TF_REGION), OMEGA, DXES, vec(EPSILON)), + E_FIELD, + ) + functional_result = functional.e_tfsf_source(TF_REGION, OMEGA, DXES, EPSILON)(E_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_e_tfsf_source_matches_sparse_operator_with_mu() -> None: + matrix_result = apply_fdfd_matrix( + operators.e_tfsf_source(vec(TF_REGION), OMEGA, DXES, vec(EPSILON), vec(MU)), + E_FIELD, + ) + functional_result = functional.e_tfsf_source(TF_REGION, OMEGA, DXES, EPSILON, MU)(E_FIELD) + + assert_fields_match(functional_result, matrix_result) + + +def test_poynting_e_cross_h_matches_sparse_operator() -> None: + matrix_result = apply_fdfd_matrix( + operators.poynting_e_cross(vec(E_FIELD), DXES), + H_FIELD, + ) + functional_result = functional.poynting_e_cross_h(DXES)(E_FIELD, H_FIELD) + + assert_fields_match(functional_result, matrix_result) diff --git a/meanas/test/test_fdfd_pml.py b/meanas/test/test_fdfd_pml.py index d752491..1a8d66c 100644 --- a/meanas/test/test_fdfd_pml.py +++ b/meanas/test/test_fdfd_pml.py @@ -1,11 +1,11 @@ -from typing import Iterable +# ruff: noqa: ARG001 import pytest # type: ignore import numpy from numpy.typing import NDArray from numpy.testing import assert_allclose from .. import fdfd -from ..fdmath import vec, unvec, dx_lists_mut +from ..fdmath import vec, unvec, dx_lists_mut, vfdfield, cfdfield_t #from .utils import assert_close, assert_fields_close from .test_fdfd import FDResult from .conftest import FixtureRequest @@ -44,49 +44,51 @@ def test_pml(sim: FDResult, src_polarity: int) -> None: # Also see conftest.py @pytest.fixture(params=[1 / 1500]) -def omega(request: FixtureRequest) -> Iterable[float]: - yield request.param +def omega(request: FixtureRequest) -> float: + return request.param @pytest.fixture(params=[None]) -def pec(request: FixtureRequest) -> Iterable[NDArray[numpy.float64] | None]: - yield request.param +def pec(request: FixtureRequest) -> NDArray[numpy.float64] | None: + return request.param @pytest.fixture(params=[None]) -def pmc(request: FixtureRequest) -> Iterable[NDArray[numpy.float64] | None]: - yield request.param +def pmc(request: FixtureRequest) -> NDArray[numpy.float64] | None: + return request.param @pytest.fixture(params=[(30, 1, 1), (1, 30, 1), (1, 1, 30)]) -def shape(request: FixtureRequest) -> Iterable[tuple[int, ...]]: - yield (3, *request.param) +def shape(request: FixtureRequest) -> tuple[int, int, int]: + return (3, *request.param) @pytest.fixture(params=[+1, -1]) -def src_polarity(request: FixtureRequest) -> Iterable[int]: - yield request.param +def src_polarity(request: FixtureRequest) -> int: + return request.param -@pytest.fixture() +@pytest.fixture def j_distribution( request: FixtureRequest, shape: tuple[int, ...], - epsilon: NDArray[numpy.float64], + epsilon: vfdfield, dxes: dx_lists_mut, omega: float, src_polarity: int, - ) -> Iterable[NDArray[numpy.complex128]]: + ) -> cfdfield_t: j = numpy.zeros(shape, dtype=complex) dim = numpy.where(numpy.array(shape[1:]) > 1)[0][0] # Propagation axis other_dims = [0, 1, 2] other_dims.remove(dim) - dx_prop = (dxes[0][dim][shape[dim + 1] // 2] - + dxes[1][dim][shape[dim + 1] // 2]) / 2 # noqa: E128 # TODO is this right for nonuniform dxes? + dx_prop = ( + dxes[0][dim][shape[dim + 1] // 2] + + dxes[1][dim][shape[dim + 1] // 2] + ) / 2 # TODO is this right for nonuniform dxes? # Mask only contains components orthogonal to propagation direction center_mask = numpy.zeros(shape, dtype=bool) @@ -106,18 +108,18 @@ def j_distribution( j = fdfd.waveguide_3d.compute_source(E=e, wavenumber=wavenumber_corrected, omega=omega, dxes=dxes, axis=dim, polarity=src_polarity, slices=slices, epsilon=epsilon) - yield j + return j -@pytest.fixture() +@pytest.fixture def epsilon( request: FixtureRequest, shape: tuple[int, ...], epsilon_bg: float, epsilon_fg: float, - ) -> Iterable[NDArray[numpy.float64]]: + ) -> NDArray[numpy.float64]: epsilon = numpy.full(shape, epsilon_fg, dtype=float) - yield epsilon + return epsilon @pytest.fixture(params=['uniform']) @@ -127,7 +129,7 @@ def dxes( dx: float, omega: float, epsilon_fg: float, - ) -> Iterable[list[list[NDArray[numpy.float64]]]]: + ) -> list[list[NDArray[numpy.float64]]]: if request.param == 'uniform': dxes = [[numpy.full(s, dx) for s in shape[1:]] for _ in range(2)] dim = numpy.where(numpy.array(shape[1:]) > 1)[0][0] # Propagation axis @@ -141,10 +143,10 @@ def dxes( epsilon_effective=epsilon_fg, thickness=10, ) - yield dxes + return dxes -@pytest.fixture() +@pytest.fixture def sim( request: FixtureRequest, shape: tuple[int, ...], @@ -162,7 +164,7 @@ def sim( omega=omega, dxes=dxes, epsilon=eps_vec, - matrix_solver_opts={'atol': 1e-15, 'tol': 1e-11}, + matrix_solver_opts={'atol': 1e-15, 'rtol': 1e-11}, ) e = unvec(e_vec, shape[1:]) diff --git a/meanas/test/test_fdfd_solvers.py b/meanas/test/test_fdfd_solvers.py new file mode 100644 index 0000000..de39d70 --- /dev/null +++ b/meanas/test/test_fdfd_solvers.py @@ -0,0 +1,128 @@ +from typing import cast + +import numpy + +from ..fdfd import solvers +from ._solver_cases import solver_plumbing_case +from .utils import assert_close + + +def test_scipy_qmr_wraps_user_callback_without_recursion(monkeypatch) -> None: + seen: list[tuple[float, ...]] = [] + + def fake_qmr(a, b: numpy.ndarray, **kwargs): + kwargs['callback'](numpy.array([1.0, 2.0])) + return numpy.array([3.0, 4.0]), 0 + + monkeypatch.setattr(solvers.scipy.sparse.linalg, 'qmr', fake_qmr) + result = solvers._scipy_qmr( + solver_plumbing_case().a0, + numpy.array([1.0, 0.0]), + callback=lambda xk: seen.append(tuple(xk)), + ) + + assert_close(result, [3.0, 4.0]) + assert seen == [(1.0, 2.0)] + + +def test_scipy_qmr_installs_logging_callback_when_missing(monkeypatch) -> None: + callback_seen: list[numpy.ndarray] = [] + + def fake_qmr(a, b: numpy.ndarray, **kwargs): + callback = kwargs['callback'] + callback(numpy.array([5.0, 6.0])) + callback_seen.append(b.copy()) + return numpy.array([7.0, 8.0]), 0 + + monkeypatch.setattr(solvers.scipy.sparse.linalg, 'qmr', fake_qmr) + result = solvers._scipy_qmr(solver_plumbing_case().a0, numpy.array([1.0, 0.0])) + + assert_close(result, [7.0, 8.0]) + assert len(callback_seen) == 1 + + +def test_generic_forward_preconditions_system_and_guess(monkeypatch) -> None: + case = solver_plumbing_case() + captured: dict[str, numpy.ndarray | float | object] = {} + + monkeypatch.setattr(solvers.operators, 'e_full', lambda *args, **kwargs: case.a0) + monkeypatch.setattr(solvers.operators, 'e_full_preconditioners', lambda dxes: (case.pl, case.pr)) + + def fake_solver(a, b: numpy.ndarray, **kwargs): + captured['a'] = a + captured['b'] = b + captured['x0'] = kwargs['x0'] + captured['atol'] = kwargs['atol'] + return case.solver_result + + result = solvers.generic( + omega=case.omega, + dxes=case.dxes, + J=case.j, + epsilon=case.epsilon, + matrix_solver=fake_solver, + matrix_solver_opts={'atol': 1e-12}, + E_guess=case.guess, + ) + + assert_close(cast(object, captured['a']).toarray(), (case.pl @ case.a0 @ case.pr).toarray()) # type: ignore[attr-defined] + assert_close(cast(numpy.ndarray, captured['b']), case.pl @ (-1j * case.omega * case.j)) + assert_close(cast(numpy.ndarray, captured['x0']), case.pl @ case.guess) + assert captured['atol'] == 1e-12 + assert_close(result, case.pr @ case.solver_result) + + +def test_generic_adjoint_preconditions_system_and_guess(monkeypatch) -> None: + case = solver_plumbing_case() + captured: dict[str, numpy.ndarray | float | object] = {} + + monkeypatch.setattr(solvers.operators, 'e_full', lambda *args, **kwargs: case.a0) + monkeypatch.setattr(solvers.operators, 'e_full_preconditioners', lambda dxes: (case.pl, case.pr)) + + def fake_solver(a, b: numpy.ndarray, **kwargs): + captured['a'] = a + captured['b'] = b + captured['x0'] = kwargs['x0'] + captured['rtol'] = kwargs['rtol'] + return case.solver_result + + result = solvers.generic( + omega=case.omega, + dxes=case.dxes, + J=case.j, + epsilon=case.epsilon, + matrix_solver=fake_solver, + matrix_solver_opts={'rtol': 1e-9}, + E_guess=case.guess, + adjoint=True, + ) + + expected_matrix = (case.pl @ case.a0 @ case.pr).T.conjugate() + assert_close(cast(object, captured['a']).toarray(), expected_matrix.toarray()) # type: ignore[attr-defined] + assert_close(cast(numpy.ndarray, captured['b']), case.pr.T.conjugate() @ (-1j * case.omega * case.j)) + assert_close(cast(numpy.ndarray, captured['x0']), case.pr.T.conjugate() @ case.guess) + assert captured['rtol'] == 1e-9 + assert_close(result, case.pl.T.conjugate() @ case.solver_result) + + +def test_generic_without_guess_does_not_inject_x0(monkeypatch) -> None: + case = solver_plumbing_case() + captured: dict[str, object] = {} + + monkeypatch.setattr(solvers.operators, 'e_full', lambda *args, **kwargs: case.a0) + monkeypatch.setattr(solvers.operators, 'e_full_preconditioners', lambda dxes: (case.pl, case.pr)) + + def fake_solver(a, b: numpy.ndarray, **kwargs): + captured['kwargs'] = kwargs + return numpy.array([1.0, -1.0]) + + result = solvers.generic( + omega=1.0, + dxes=case.dxes, + J=numpy.array([2.0, 3.0]), + epsilon=case.epsilon, + matrix_solver=fake_solver, + ) + + assert 'x0' not in cast(dict[str, object], captured['kwargs']) + assert_close(result, case.pr @ numpy.array([1.0, -1.0])) diff --git a/meanas/test/test_fdmath_functional.py b/meanas/test/test_fdmath_functional.py new file mode 100644 index 0000000..368eba3 --- /dev/null +++ b/meanas/test/test_fdmath_functional.py @@ -0,0 +1,60 @@ +import numpy + +from ..fdmath import functional as fd_functional +from ..fdmath import operators as fd_operators +from ..fdmath import vec, unvec +from .utils import assert_close, assert_fields_close + + +SHAPE = (2, 3, 2) +DX_E = [numpy.array([1.0, 1.5]), numpy.array([0.75, 1.25, 1.5]), numpy.array([1.2, 0.8])] +DX_H = [numpy.array([0.9, 1.4]), numpy.array([0.8, 1.1, 1.4]), numpy.array([1.0, 0.7])] + +SCALAR_FIELD = ( + numpy.arange(numpy.prod(SHAPE)).reshape(SHAPE) + + 0.1j * numpy.arange(numpy.prod(SHAPE)).reshape(SHAPE) +).astype(complex) +VECTOR_FIELD = (numpy.arange(3 * numpy.prod(SHAPE)).reshape((3, *SHAPE)) + 0.25j).astype(complex) + + +def test_deriv_forward_without_dx_matches_numpy_roll() -> None: + for axis, deriv in enumerate(fd_functional.deriv_forward()): + expected = numpy.roll(SCALAR_FIELD, -1, axis=axis) - SCALAR_FIELD + assert_close(deriv(SCALAR_FIELD), expected) + + +def test_deriv_back_without_dx_matches_numpy_roll() -> None: + for axis, deriv in enumerate(fd_functional.deriv_back()): + expected = SCALAR_FIELD - numpy.roll(SCALAR_FIELD, 1, axis=axis) + assert_close(deriv(SCALAR_FIELD), expected) + + +def test_curl_parts_sum_to_full_curl() -> None: + curl_forward = fd_functional.curl_forward(DX_E)(VECTOR_FIELD) + curl_back = fd_functional.curl_back(DX_H)(VECTOR_FIELD) + forward_parts = fd_functional.curl_forward_parts(DX_E)(VECTOR_FIELD) + back_parts = fd_functional.curl_back_parts(DX_H)(VECTOR_FIELD) + + for axis in range(3): + assert_close(forward_parts[axis][0] + forward_parts[axis][1], curl_forward[axis]) + assert_close(back_parts[axis][0] + back_parts[axis][1], curl_back[axis]) + + +def test_derivatives_match_sparse_operators_on_nonuniform_grid() -> None: + for axis, deriv in enumerate(fd_functional.deriv_forward(DX_E)): + matrix_result = (fd_operators.deriv_forward(DX_E)[axis] @ SCALAR_FIELD.ravel(order='C')).reshape(SHAPE, order='C') + assert_close(deriv(SCALAR_FIELD), matrix_result, atol=1e-12, rtol=1e-12) + + for axis, deriv in enumerate(fd_functional.deriv_back(DX_H)): + matrix_result = (fd_operators.deriv_back(DX_H)[axis] @ SCALAR_FIELD.ravel(order='C')).reshape(SHAPE, order='C') + assert_close(deriv(SCALAR_FIELD), matrix_result, atol=1e-12, rtol=1e-12) + + +def test_curls_match_sparse_operators_on_nonuniform_grid() -> None: + curl_forward = fd_functional.curl_forward(DX_E)(VECTOR_FIELD) + curl_back = fd_functional.curl_back(DX_H)(VECTOR_FIELD) + matrix_forward = unvec(fd_operators.curl_forward(DX_E) @ vec(VECTOR_FIELD), SHAPE) + matrix_back = unvec(fd_operators.curl_back(DX_H) @ vec(VECTOR_FIELD), SHAPE) + + assert_fields_close(curl_forward, matrix_forward, atol=1e-12, rtol=1e-12) + assert_fields_close(curl_back, matrix_back, atol=1e-12, rtol=1e-12) diff --git a/meanas/test/test_fdmath_operators.py b/meanas/test/test_fdmath_operators.py new file mode 100644 index 0000000..9b1dec0 --- /dev/null +++ b/meanas/test/test_fdmath_operators.py @@ -0,0 +1,90 @@ +import numpy +import pytest + +from ..fdmath import operators, unvec, vec +from ._test_builders import real_ramp +from .utils import assert_close + + +SHAPE = (2, 3, 2) +SCALAR_FIELD = real_ramp(SHAPE) +VECTOR_LEFT = real_ramp((3, *SHAPE), offset=0.5) +VECTOR_RIGHT = real_ramp((3, *SHAPE), scale=1 / 3, offset=2.0) + + +def _apply_scalar_matrix(op: operators.sparse.spmatrix) -> numpy.ndarray: + return (op @ SCALAR_FIELD.ravel(order='C')).reshape(SHAPE, order='C') + + +def _mirrored_indices(size: int, shift_distance: int) -> numpy.ndarray: + indices = numpy.arange(size) + shift_distance + indices = numpy.where(indices >= size, 2 * size - indices - 1, indices) + indices = numpy.where(indices < 0, -1 - indices, indices) + return indices + + +@pytest.mark.parametrize(('axis', 'shift_distance'), [(0, 1), (1, -1), (2, 1)]) +def test_shift_circ_matches_numpy_roll(axis: int, shift_distance: int) -> None: + matrix_result = _apply_scalar_matrix(operators.shift_circ(axis, SHAPE, shift_distance)) + expected = numpy.roll(SCALAR_FIELD, -shift_distance, axis=axis) + assert_close(matrix_result, expected) + + +@pytest.mark.parametrize(('axis', 'shift_distance'), [(0, 1), (1, -1), (2, 1)]) +def test_shift_with_mirror_matches_explicit_mirrored_indices(axis: int, shift_distance: int) -> None: + matrix_result = _apply_scalar_matrix(operators.shift_with_mirror(axis, SHAPE, shift_distance)) + indices = [numpy.arange(length) for length in SHAPE] + indices[axis] = _mirrored_indices(SHAPE[axis], shift_distance) + expected = SCALAR_FIELD[numpy.ix_(*indices)] + assert_close(matrix_result, expected) + + +@pytest.mark.parametrize( + ('args', 'message'), + [ + ((0, (2,), 1), 'Invalid shape'), + ((3, SHAPE, 1), 'Invalid direction'), + ], + ) +def test_shift_circ_rejects_invalid_arguments(args: tuple[int, tuple[int, ...], int], message: str) -> None: + with pytest.raises(Exception, match=message): + operators.shift_circ(*args) + + +@pytest.mark.parametrize( + ('args', 'message'), + [ + ((0, (2,), 1), 'Invalid shape'), + ((3, SHAPE, 1), 'Invalid direction'), + ((0, SHAPE, SHAPE[0]), 'too large'), + ], + ) +def test_shift_with_mirror_rejects_invalid_arguments(args: tuple[int, tuple[int, ...], int], message: str) -> None: + with pytest.raises(Exception, match=message): + operators.shift_with_mirror(*args) + + +def test_vec_cross_matches_pointwise_cross_product() -> None: + matrix_result = unvec(operators.vec_cross(vec(VECTOR_LEFT)) @ vec(VECTOR_RIGHT), SHAPE) + expected = numpy.empty_like(VECTOR_LEFT) + expected[0] = VECTOR_LEFT[1] * VECTOR_RIGHT[2] - VECTOR_LEFT[2] * VECTOR_RIGHT[1] + expected[1] = VECTOR_LEFT[2] * VECTOR_RIGHT[0] - VECTOR_LEFT[0] * VECTOR_RIGHT[2] + expected[2] = VECTOR_LEFT[0] * VECTOR_RIGHT[1] - VECTOR_LEFT[1] * VECTOR_RIGHT[0] + assert_close(matrix_result, expected) + + +def test_avg_forward_matches_half_sum_with_forward_neighbor() -> None: + matrix_result = _apply_scalar_matrix(operators.avg_forward(1, SHAPE)) + expected = 0.5 * (SCALAR_FIELD + numpy.roll(SCALAR_FIELD, -1, axis=1)) + assert_close(matrix_result, expected) + + +def test_avg_back_matches_half_sum_with_backward_neighbor() -> None: + matrix_result = _apply_scalar_matrix(operators.avg_back(1, SHAPE)) + expected = 0.5 * (SCALAR_FIELD + numpy.roll(SCALAR_FIELD, 1, axis=1)) + assert_close(matrix_result, expected) + + +def test_avg_forward_rejects_invalid_shape() -> None: + with pytest.raises(Exception, match='Invalid shape'): + operators.avg_forward(0, (2,)) diff --git a/meanas/test/test_fdmath_vectorization.py b/meanas/test/test_fdmath_vectorization.py new file mode 100644 index 0000000..c55f7cd --- /dev/null +++ b/meanas/test/test_fdmath_vectorization.py @@ -0,0 +1,46 @@ +import numpy + +from ..fdmath import unvec, vec +from ._test_builders import complex_ramp, real_ramp +from .utils import assert_close + + +SHAPE = (2, 3, 2) +FIELD = real_ramp((3, *SHAPE)) +COMPLEX_FIELD = complex_ramp((3, *SHAPE), imag_scale=0.5) + + +def test_vec_and_unvec_return_none_for_none_input() -> None: + assert vec(None) is None + assert unvec(None, SHAPE) is None + + +def test_real_field_round_trip_preserves_shape_and_values() -> None: + vector = vec(FIELD) + assert vector is not None + restored = unvec(vector, SHAPE) + assert restored is not None + assert restored.shape == (3, *SHAPE) + assert_close(restored, FIELD) + + +def test_complex_field_round_trip_preserves_shape_and_values() -> None: + vector = vec(COMPLEX_FIELD) + assert vector is not None + restored = unvec(vector, SHAPE) + assert restored is not None + assert restored.shape == (3, *SHAPE) + assert_close(restored, COMPLEX_FIELD) + + +def test_unvec_with_two_components_round_trips_vector() -> None: + vector = numpy.arange(2 * numpy.prod(SHAPE), dtype=float) + field = unvec(vector, SHAPE, nvdim=2) + assert field is not None + assert field.shape == (2, *SHAPE) + assert_close(vec(field), vector) + + +def test_vec_accepts_arraylike_input() -> None: + arraylike = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] + assert_close(vec(arraylike), numpy.ravel(arraylike, order='C')) diff --git a/meanas/test/test_fdtd.py b/meanas/test/test_fdtd.py index 0a92c73..469c220 100644 --- a/meanas/test/test_fdtd.py +++ b/meanas/test/test_fdtd.py @@ -1,4 +1,5 @@ -from typing import Iterable, Any +# ruff: noqa: ARG001 +from typing import Any import dataclasses import pytest # type: ignore import numpy @@ -6,7 +7,7 @@ from numpy.typing import NDArray #from numpy.testing import assert_allclose, assert_array_equal from .. import fdtd -from .utils import assert_close, assert_fields_close, PRNG +from .utils import assert_close, assert_fields_close, make_prng from .conftest import FixtureRequest @@ -150,8 +151,8 @@ def test_poynting_planes(sim: 'TDResult') -> None: @pytest.fixture(params=[0.3]) -def dt(request: FixtureRequest) -> Iterable[float]: - yield request.param +def dt(request: FixtureRequest) -> float: + return request.param @dataclasses.dataclass() @@ -168,8 +169,8 @@ class TDResult: @pytest.fixture(params=[(0, 4, 8)]) # (0,) -def j_steps(request: FixtureRequest) -> Iterable[tuple[int, ...]]: - yield request.param +def j_steps(request: FixtureRequest) -> tuple[int, ...]: + return request.param @pytest.fixture(params=['center', 'random']) @@ -177,18 +178,19 @@ def j_distribution( request: FixtureRequest, shape: tuple[int, ...], j_mag: float, - ) -> Iterable[NDArray[numpy.float64]]: + ) -> NDArray[numpy.float64]: + prng = make_prng() j = numpy.zeros(shape) if request.param == 'center': j[:, shape[1] // 2, shape[2] // 2, shape[3] // 2] = j_mag elif request.param == '000': j[:, 0, 0, 0] = j_mag elif request.param == 'random': - j[:] = PRNG.uniform(low=-j_mag, high=j_mag, size=shape) - yield j + j[:] = prng.uniform(low=-j_mag, high=j_mag, size=shape) + return j -@pytest.fixture() +@pytest.fixture def sim( request: FixtureRequest, shape: tuple[int, ...], @@ -199,9 +201,8 @@ def sim( j_steps: tuple[int, ...], ) -> TDResult: is3d = (numpy.array(shape) == 1).sum() == 0 - if is3d: - if dt != 0.3: - pytest.skip('Skipping dt != 0.3 because test is 3D (for speed)') + if is3d and dt != 0.3: + pytest.skip('Skipping dt != 0.3 because test is 3D (for speed)') sim = TDResult( shape=shape, diff --git a/meanas/test/test_fdtd_base.py b/meanas/test/test_fdtd_base.py new file mode 100644 index 0000000..c8246d5 --- /dev/null +++ b/meanas/test/test_fdtd_base.py @@ -0,0 +1,43 @@ +from ..fdmath import functional as fd_functional +from ..fdtd import base +from ._test_builders import real_ramp +from .utils import assert_close + + +DT = 0.25 +SHAPE = (3, 2, 2, 2) +E_FIELD = real_ramp(SHAPE, scale=1 / 5) +H_FIELD = real_ramp(SHAPE, scale=1 / 7, offset=1 / 7) +EPSILON = 1.5 + E_FIELD / 10.0 +MU_FIELD = 2.0 + H_FIELD / 8.0 +MU_SCALAR = 3.0 + + +def test_maxwell_e_without_dxes_matches_unit_spacing_update() -> None: + updater = base.maxwell_e(dt=DT) + expected = E_FIELD + DT * fd_functional.curl_back()(H_FIELD) / EPSILON + + updated = updater(E_FIELD.copy(), H_FIELD.copy(), EPSILON) + + assert_close(updated, expected) + + +def test_maxwell_h_without_dxes_and_without_mu_matches_unit_spacing_update() -> None: + updater = base.maxwell_h(dt=DT) + expected = H_FIELD - DT * fd_functional.curl_forward()(E_FIELD) + + updated = updater(E_FIELD.copy(), H_FIELD.copy()) + + assert_close(updated, expected) + + +def test_maxwell_h_without_dxes_accepts_scalar_and_field_mu() -> None: + updater = base.maxwell_h(dt=DT) + + updated_scalar = updater(E_FIELD.copy(), H_FIELD.copy(), MU_SCALAR) + expected_scalar = H_FIELD - DT * fd_functional.curl_forward()(E_FIELD) / MU_SCALAR + assert_close(updated_scalar, expected_scalar) + + updated_field = updater(E_FIELD.copy(), H_FIELD.copy(), MU_FIELD) + expected_field = H_FIELD - DT * fd_functional.curl_forward()(E_FIELD) / MU_FIELD + assert_close(updated_field, expected_field) diff --git a/meanas/test/test_fdtd_boundaries.py b/meanas/test/test_fdtd_boundaries.py new file mode 100644 index 0000000..d60ca7a --- /dev/null +++ b/meanas/test/test_fdtd_boundaries.py @@ -0,0 +1,62 @@ +import numpy +import pytest +from numpy.testing import assert_allclose + +from ..fdtd.boundaries import conducting_boundary + + +def _axis_index(axis: int, index: int) -> tuple[slice | int, ...]: + coords: list[slice | int] = [slice(None), slice(None), slice(None)] + coords[axis] = index + return tuple(coords) + + +@pytest.mark.parametrize('direction', [0, 1, 2]) +@pytest.mark.parametrize('polarity', [-1, 1]) +def test_conducting_boundary_updates_expected_faces(direction: int, polarity: int) -> None: + e = numpy.arange(3 * 4 * 4 * 4, dtype=float).reshape(3, 4, 4, 4) + h = e.copy() + e0 = e.copy() + h0 = h.copy() + + update_e, update_h = conducting_boundary(direction, polarity) + update_e(e) + update_h(h) + + dirs = [0, 1, 2] + dirs.remove(direction) + u, v = dirs + + if polarity < 0: + boundary = _axis_index(direction, 0) + shifted1 = _axis_index(direction, 1) + + assert_allclose(e[direction][boundary], 0) + assert_allclose(e[u][boundary], e0[u][shifted1]) + assert_allclose(e[v][boundary], e0[v][shifted1]) + assert_allclose(h[direction][boundary], h0[direction][shifted1]) + assert_allclose(h[u][boundary], 0) + assert_allclose(h[v][boundary], 0) + else: + boundary = _axis_index(direction, -1) + shifted1 = _axis_index(direction, -2) + shifted2 = _axis_index(direction, -3) + + assert_allclose(e[direction][boundary], -e0[direction][shifted2]) + assert_allclose(e[direction][shifted1], 0) + assert_allclose(e[u][boundary], e0[u][shifted1]) + assert_allclose(e[v][boundary], e0[v][shifted1]) + assert_allclose(h[direction][boundary], h0[direction][shifted1]) + assert_allclose(h[u][boundary], -h0[u][shifted2]) + assert_allclose(h[u][shifted1], 0) + assert_allclose(h[v][boundary], -h0[v][shifted2]) + assert_allclose(h[v][shifted1], 0) + + +@pytest.mark.parametrize( + ('direction', 'polarity'), + [(-1, 1), (3, 1), (0, 0)], +) +def test_conducting_boundary_rejects_invalid_arguments(direction: int, polarity: int) -> None: + with pytest.raises(ValueError, match='Invalid direction|Bad polarity'): + conducting_boundary(direction, polarity) diff --git a/meanas/test/test_fdtd_energy.py b/meanas/test/test_fdtd_energy.py new file mode 100644 index 0000000..84830cf --- /dev/null +++ b/meanas/test/test_fdtd_energy.py @@ -0,0 +1,99 @@ +import numpy + +from .. import fdtd +from ..fdtd import energy as fdtd_energy +from ._test_builders import real_ramp, unit_dxes +from .utils import assert_close + + +SHAPE = (2, 2, 2) +DT = 0.25 +UNIT_DXES = unit_dxes(SHAPE) +DXES = ( + ( + numpy.array([1.0, 1.5]), + numpy.array([0.75, 1.25]), + numpy.array([1.1, 0.9]), + ), + ( + numpy.array([0.8, 1.2]), + numpy.array([1.4, 0.6]), + numpy.array([0.7, 1.3]), + ), +) +E0 = real_ramp((3, *SHAPE)) +E1 = E0 + 0.5 +E2 = E0 + 1.0 +E3 = E0 + 1.5 +H0 = real_ramp((3, *SHAPE), scale=1 / 3, offset=2 / 3) +H1 = H0 + 0.25 +H2 = H0 + 0.5 +H3 = H0 + 0.75 +J0 = (E0 + 2.0) / 5.0 +EPSILON = 1.0 + E0 / 20.0 +MU = 1.5 + H0 / 10.0 + + +def test_poynting_default_spacing_matches_explicit_unit_spacing() -> None: + default_spacing = fdtd.poynting(E1, H1) + explicit_spacing = fdtd.poynting(E1, H1, dxes=UNIT_DXES) + assert_close(default_spacing, explicit_spacing) + + +def test_poynting_divergence_matches_precomputed_poynting_vector() -> None: + s = fdtd.poynting(E2, H2, dxes=DXES) + from_fields = fdtd.poynting_divergence(e=E2, h=H2, dxes=DXES) + from_vector = fdtd.poynting_divergence(s=s) + assert_close(from_fields, from_vector) + + +def test_delta_energy_h2e_matches_direct_dxmul_formula() -> None: + expected = fdtd_energy.dxmul( + E2 * (E2 - E0) / DT, + H1 * (H3 - H1) / DT, + EPSILON, + MU, + DXES, + ) + actual = fdtd.delta_energy_h2e( + dt=DT, + e0=E0, + h1=H1, + e2=E2, + h3=H3, + epsilon=EPSILON, + mu=MU, + dxes=DXES, + ) + assert_close(actual, expected) + + +def test_delta_energy_e2h_matches_direct_dxmul_formula() -> None: + expected = fdtd_energy.dxmul( + E1 * (E3 - E1) / DT, + H2 * (H2 - H0) / DT, + EPSILON, + MU, + DXES, + ) + actual = fdtd_energy.delta_energy_e2h( + dt=DT, + h0=H0, + e1=E1, + h2=H2, + e3=E3, + epsilon=EPSILON, + mu=MU, + dxes=DXES, + ) + assert_close(actual, expected) + + +def test_delta_energy_j_defaults_to_unit_cell_volume() -> None: + expected = (J0 * E1).sum(axis=0) + assert_close(fdtd.delta_energy_j(j0=J0, e1=E1), expected) + + +def test_dxmul_defaults_to_unit_materials_and_spacing() -> None: + expected = E1.sum(axis=0) + H1.sum(axis=0) + assert_close(fdtd_energy.dxmul(E1, H1), expected) diff --git a/meanas/test/test_fdtd_misc.py b/meanas/test/test_fdtd_misc.py new file mode 100644 index 0000000..3688c6c --- /dev/null +++ b/meanas/test/test_fdtd_misc.py @@ -0,0 +1,45 @@ +import numpy +import pytest + +from ..fdtd.misc import gaussian_beam, gaussian_packet, ricker_pulse + + +@pytest.mark.parametrize('one_sided', [False, True]) +def test_gaussian_packet_accepts_array_input(one_sided: bool) -> None: + dt = 0.01 + source, delay = gaussian_packet(1.55, 0.1, dt, one_sided=one_sided) + steps = numpy.array([0, int(numpy.ceil(delay / dt)) + 5]) + envelope, cc, ss = source(steps) + assert isinstance(envelope, numpy.ndarray) + assert isinstance(cc, numpy.ndarray) + assert isinstance(ss, numpy.ndarray) + + assert envelope.shape == (2,) + assert numpy.isfinite(envelope).all() + assert numpy.isfinite(cc).all() + assert numpy.isfinite(ss).all() + if one_sided: + assert envelope[-1] == pytest.approx(1.0) + + +def test_ricker_pulse_returns_finite_values() -> None: + source, delay = ricker_pulse(1.55, 0.01) + envelope, cc, ss = source(numpy.array([0, 1, 2])) + + assert numpy.isfinite(delay) + assert numpy.isfinite(envelope).all() + assert numpy.isfinite(cc).all() + assert numpy.isfinite(ss).all() + + +def test_gaussian_beam_centered_grid_is_finite_and_normalized() -> None: + beam = gaussian_beam( + xyz=[numpy.linspace(-1, 1, 3), numpy.linspace(-1, 1, 3), numpy.linspace(-1, 1, 3)], + center=[0, 0, 0], + waist_radius=1.0, + wl=1.55, + ) + + row = beam[:, :, beam.shape[2] // 2] + assert numpy.isfinite(beam).all() + assert numpy.linalg.norm(row) == pytest.approx(1.0) diff --git a/meanas/test/test_fdtd_phasor.py b/meanas/test/test_fdtd_phasor.py new file mode 100644 index 0000000..9d28ee3 --- /dev/null +++ b/meanas/test/test_fdtd_phasor.py @@ -0,0 +1,403 @@ +import dataclasses +from functools import lru_cache + +import numpy +import pytest +import scipy.sparse.linalg + +from .. import fdfd, fdtd +from ..fdtd.misc import gaussian_packet +from ..fdmath import unvec, vec +from ._test_builders import unit_dxes +from .utils import assert_close, assert_fields_close + + +@dataclasses.dataclass(frozen=True) +class ContinuousWaveCase: + omega: float + dt: float + dxes: tuple[tuple[numpy.ndarray, ...], tuple[numpy.ndarray, ...]] + epsilon: numpy.ndarray + e_ph: numpy.ndarray + h_ph: numpy.ndarray + j_ph: numpy.ndarray + snapshots: tuple['RealFieldSnapshot', ...] + + +@dataclasses.dataclass(frozen=True) +class RealPulseCase: + omega: float + dt: float + j_ph: numpy.ndarray + target_j_ph: numpy.ndarray + + +@dataclasses.dataclass(frozen=True) +class RealFieldSnapshot: + step: int + j_field: numpy.ndarray + e_field: numpy.ndarray + h_field: numpy.ndarray + + +def test_phasor_accumulator_matches_direct_sum_for_multi_frequency_weights() -> None: + omegas = numpy.array([0.25, 0.5]) + dt = 0.2 + sample_0 = numpy.array([[1.0, 2.0], [3.0, 4.0]]) + sample_1 = numpy.array([[0.5, 1.5], [2.5, 3.5]]) + weight_0 = numpy.array([1.0, 2.0]) + weight_1 = 0.75 + accumulator = numpy.zeros((omegas.size, *sample_0.shape), dtype=complex) + + fdtd.accumulate_phasor(accumulator, omegas, dt, sample_0, 0, weight=weight_0) + fdtd.accumulate_phasor(accumulator, omegas, dt, sample_1, 3, offset_steps=0.5, weight=weight_1) + + expected = numpy.zeros((2, *sample_0.shape), dtype=complex) + for idx, omega in enumerate(omegas): + expected[idx] += dt * weight_0[idx] * numpy.exp(-1j * omega * 0.0) * sample_0 + expected[idx] += dt * weight_1 * numpy.exp(-1j * omega * ((3 + 0.5) * dt)) * sample_1 + + assert_close(accumulator, expected) + + +def test_phasor_accumulator_convenience_methods_apply_yee_offsets() -> None: + omega = 1.25 + dt = 0.1 + sample = numpy.arange(6, dtype=float).reshape(2, 3) + e_acc = numpy.zeros((1, *sample.shape), dtype=complex) + h_acc = numpy.zeros((1, *sample.shape), dtype=complex) + j_acc = numpy.zeros((1, *sample.shape), dtype=complex) + + fdtd.accumulate_phasor_e(e_acc, omega, dt, sample, 4) + fdtd.accumulate_phasor_h(h_acc, omega, dt, sample, 4) + fdtd.accumulate_phasor_j(j_acc, omega, dt, sample, 4) + + expected_e = dt * numpy.exp(-1j * omega * (4 * dt)) * sample + expected_h = dt * numpy.exp(-1j * omega * ((4.5) * dt)) * sample + + assert_close(e_acc[0], expected_e) + assert_close(h_acc[0], expected_h) + assert_close(j_acc[0], expected_h) + + +def test_phasor_accumulator_matches_delayed_weighted_example_pattern() -> None: + omega = 0.75 + dt = 0.2 + delay = 0.6 + phasor_norm = 0.5 + steps = numpy.arange(5) + samples = numpy.arange(20, dtype=float).reshape(5, 2, 2) + 1.0 + accumulator = numpy.zeros((1, 2, 2), dtype=complex) + + for step, sample in zip(steps, samples, strict=True): + fdtd.accumulate_phasor( + accumulator, + omega, + dt, + sample, + int(step), + offset_steps=0.5 - delay / dt, + weight=phasor_norm / dt, + ) + + expected = numpy.zeros((2, 2), dtype=complex) + for step, sample in zip(steps, samples, strict=True): + time = (step + 0.5 - delay / dt) * dt + expected += dt * (phasor_norm / dt) * numpy.exp(-1j * omega * time) * sample + + assert_close(accumulator[0], expected) + + +def test_temporal_phasor_matches_direct_sum_for_offset_waveform() -> None: + omegas = numpy.array([0.75, 1.25]) + dt = 0.2 + samples = numpy.array([1.0 + 0.5j, 0.5 - 0.25j, -0.75 + 0.1j]) + + result = fdtd.temporal_phasor(samples, omegas, dt, start_step=2, offset_steps=0.5) + + expected = numpy.zeros(omegas.shape, dtype=complex) + for idx, omega in enumerate(omegas): + for step, sample in enumerate(samples, start=2): + expected[idx] += dt * numpy.exp(-1j * omega * ((step + 0.5) * dt)) * sample + + assert_close(result, expected) + + +def test_temporal_phasor_scale_normalizes_waveform_to_target_response() -> None: + omega = 0.75 + dt = 0.2 + delay = 0.6 + samples = numpy.arange(5, dtype=float) + 1.0 + scale = fdtd.temporal_phasor_scale(samples, omega, dt, offset_steps=0.5 - delay / dt, target=0.5) + normalized = fdtd.temporal_phasor(scale[0] * samples, omega, dt, offset_steps=0.5 - delay / dt) + + assert_close(normalized[0], 0.5) + + +def test_real_injection_scale_matches_positive_frequency_normalization() -> None: + omega = 0.75 + dt = 0.2 + samples = numpy.array([1.0 + 0.5j, 0.5 - 0.25j, -0.75 + 0.1j]) + scale = fdtd.real_injection_scale(samples, omega, dt, offset_steps=0.5, target=0.5) + normalized = 0.5 * scale[0] * fdtd.temporal_phasor(samples, omega, dt, offset_steps=0.5)[0] + + assert_close(normalized, 0.5) + + +def test_reconstruct_real_matches_direct_formula_and_yee_wrappers() -> None: + omegas = numpy.array([0.75, 1.25]) + dt = 0.2 + phasors = numpy.array( + [ + [[1.0 + 2.0j, -0.5 + 0.25j]], + [[-1.5 + 0.5j, 0.75 - 0.125j]], + ], + dtype=complex, + ) + + reconstructed = fdtd.reconstruct_real(phasors, omegas, dt, 3, offset_steps=0.5) + expected = numpy.stack( + [ + numpy.real(phasors[idx] * numpy.exp(1j * omega * ((3.5) * dt))) + for idx, omega in enumerate(omegas) + ], + ) + + assert_close(reconstructed, expected) + assert_close(fdtd.reconstruct_real_e(phasors[:1], omegas[0], dt, 3)[0], numpy.real(phasors[0] * numpy.exp(1j * omegas[0] * (3 * dt)))) + assert_close(fdtd.reconstruct_real_h(phasors[:1], omegas[0], dt, 3)[0], numpy.real(phasors[0] * numpy.exp(1j * omegas[0] * ((3.5) * dt)))) + assert_close(fdtd.reconstruct_real_j(phasors[:1], omegas[0], dt, 3)[0], numpy.real(phasors[0] * numpy.exp(1j * omegas[0] * ((3.5) * dt)))) + + +def test_reconstruct_real_accepts_scalar_frequency_without_leading_axis() -> None: + omega = 0.75 + dt = 0.2 + phasor = numpy.array([[1.0 + 0.5j, -0.25 + 0.75j]]) + + reconstructed = fdtd.reconstruct_real(phasor, omega, dt, 3, offset_steps=0.5) + expected = numpy.real(phasor * numpy.exp(1j * omega * ((3.5) * dt))) + + assert_close(reconstructed, expected) + assert_close(fdtd.reconstruct_real_e(phasor, omega, dt, 3), numpy.real(phasor * numpy.exp(1j * omega * (3 * dt)))) + assert_close(fdtd.reconstruct_real_h(phasor, omega, dt, 3), expected) + assert_close(fdtd.reconstruct_real_j(phasor, omega, dt, 3), expected) + + +def test_phasor_accumulator_validation_reset_and_temporal_validation() -> None: + with pytest.raises(ValueError, match='dt must be positive'): + fdtd.accumulate_phasor(numpy.zeros((1, 2, 2), dtype=complex), [1.0], 0.0, numpy.ones((2, 2)), 0) + + with pytest.raises(ValueError, match='omegas must be a scalar or non-empty 1D sequence'): + fdtd.accumulate_phasor(numpy.zeros((1, 2, 2), dtype=complex), numpy.ones((2, 2)), 0.2, numpy.ones((2, 2)), 0) + + accumulator = numpy.zeros((2, 2, 2), dtype=complex) + + with pytest.raises(ValueError, match='accumulator must have shape'): + fdtd.accumulate_phasor(accumulator, [1.0], 0.2, numpy.ones((2, 2)), 0) + + with pytest.raises(ValueError, match='weight must be scalar'): + fdtd.accumulate_phasor(accumulator, [1.0, 2.0], 0.2, numpy.ones((2, 2)), 0, weight=numpy.ones((2, 2))) + + fdtd.accumulate_phasor(accumulator, [1.0, 2.0], 0.2, numpy.ones((2, 2)), 0) + accumulator.fill(0) + assert_close(accumulator, 0.0) + + with pytest.raises(ValueError, match='samples must be a non-empty 1D sequence'): + fdtd.temporal_phasor(numpy.ones((2, 2)), [1.0], 0.2) + + with pytest.raises(ValueError, match='cannot normalize a waveform with zero temporal phasor response'): + fdtd.temporal_phasor_scale(numpy.zeros(4), [1.0], 0.2) + + with pytest.raises(ValueError, match='cannot normalize a waveform with zero temporal phasor response'): + fdtd.real_injection_scale(numpy.zeros(4), [1.0], 0.2) + + with pytest.raises(ValueError, match='dt must be positive'): + fdtd.reconstruct_real(numpy.ones((1, 2, 2), dtype=complex), [1.0], 0.0, 0) + + with pytest.raises(ValueError, match='omegas must be a scalar or non-empty 1D sequence'): + fdtd.reconstruct_real(numpy.ones((1, 2, 2), dtype=complex), numpy.ones((2, 2)), 0.2, 0) + + with pytest.raises(ValueError, match='phasors must have shape'): + fdtd.reconstruct_real(numpy.ones((3, 2, 2), dtype=complex), [1.0, 2.0], 0.2, 0) + + +@lru_cache(maxsize=1) +def _continuous_wave_case() -> ContinuousWaveCase: + spatial_shape = (5, 1, 5) + full_shape = (3, *spatial_shape) + dt = 0.25 + period_steps = 64 + warmup_periods = 8 + accumulation_periods = 8 + omega = 2 * numpy.pi / (period_steps * dt) + total_steps = period_steps * (warmup_periods + accumulation_periods) + warmup_steps = period_steps * warmup_periods + accumulation_steps = period_steps * accumulation_periods + source_amplitude = 1.0 + source_index = (1, spatial_shape[0] // 2, spatial_shape[1] // 2, spatial_shape[2] // 2) + + dxes = unit_dxes(spatial_shape) + epsilon = numpy.ones(full_shape, dtype=float) + e_field = numpy.zeros(full_shape, dtype=float) + h_field = numpy.zeros(full_shape, dtype=float) + update_e = fdtd.maxwell_e(dt=dt, dxes=dxes) + update_h = fdtd.maxwell_h(dt=dt, dxes=dxes) + + e_accumulator = numpy.zeros((1, *full_shape), dtype=complex) + h_accumulator = numpy.zeros((1, *full_shape), dtype=complex) + j_accumulator = numpy.zeros((1, *full_shape), dtype=complex) + snapshot_offsets = (0, period_steps // 4, period_steps // 2, 3 * period_steps // 4) + snapshot_steps = { + warmup_steps + accumulation_steps - period_steps + offset + for offset in snapshot_offsets + } + snapshots: list[RealFieldSnapshot] = [] + + for step in range(total_steps): + update_e(e_field, h_field, epsilon) + + j_step = numpy.zeros_like(e_field) + current_density = source_amplitude * numpy.cos(omega * (step + 0.5) * dt) + j_step[source_index] = current_density + e_field -= dt * j_step / epsilon + + if step >= warmup_steps: + fdtd.accumulate_phasor_j(j_accumulator, omega, dt, j_step, step) + fdtd.accumulate_phasor_e(e_accumulator, omega, dt, e_field, step + 1) + + update_h(e_field, h_field) + + if step in snapshot_steps: + snapshots.append( + RealFieldSnapshot( + step=step, + j_field=j_step.copy(), + e_field=e_field.copy(), + h_field=h_field.copy(), + ), + ) + + if step >= warmup_steps: + fdtd.accumulate_phasor_h(h_accumulator, omega, dt, h_field, step + 1) + + return ContinuousWaveCase( + omega=omega, + dt=dt, + dxes=dxes, + epsilon=epsilon, + e_ph=e_accumulator[0], + h_ph=h_accumulator[0], + j_ph=j_accumulator[0], + snapshots=tuple(snapshots), + ) + + +def test_continuous_wave_current_phasor_matches_analytic_discrete_sum() -> None: + case = _continuous_wave_case() + + accumulation_indices = numpy.arange(64 * 8, 64 * 16) + times = (accumulation_indices + 0.5) * case.dt + expected = numpy.zeros_like(case.j_ph) + expected[1, 2, 0, 2] = case.dt * numpy.sum( + numpy.exp(-1j * case.omega * times) * numpy.cos(case.omega * times), + ) + + assert_fields_close(case.j_ph, expected, atol=1e-12, rtol=1e-12) + + +def test_continuous_wave_electric_phasor_matches_fdfd_solution() -> None: + case = _continuous_wave_case() + operator = fdfd.operators.e_full(case.omega, case.dxes, vec(case.epsilon)).tocsr() + rhs = -1j * case.omega * vec(case.j_ph) + e_fdfd = unvec(scipy.sparse.linalg.spsolve(operator, rhs), case.epsilon.shape[1:]) + + rel_err = numpy.linalg.norm(vec(case.e_ph - e_fdfd)) / numpy.linalg.norm(vec(e_fdfd)) + assert rel_err < 5e-2 + + +def test_continuous_wave_magnetic_phasor_matches_fdfd_conversion() -> None: + case = _continuous_wave_case() + operator = fdfd.operators.e_full(case.omega, case.dxes, vec(case.epsilon)).tocsr() + rhs = -1j * case.omega * vec(case.j_ph) + e_fdfd = unvec(scipy.sparse.linalg.spsolve(operator, rhs), case.epsilon.shape[1:]) + h_fdfd = fdfd.functional.e2h(case.omega, case.dxes)(e_fdfd) + + rel_err = numpy.linalg.norm(vec(case.h_ph - h_fdfd)) / numpy.linalg.norm(vec(h_fdfd)) + assert rel_err < 5e-2 + + +def test_continuous_wave_extracted_electric_phasor_has_small_fdfd_residual() -> None: + case = _continuous_wave_case() + operator = fdfd.operators.e_full(case.omega, case.dxes, vec(case.epsilon)).tocsr() + rhs = -1j * case.omega * vec(case.j_ph) + residual = operator @ vec(case.e_ph) - rhs + rel_residual = numpy.linalg.norm(residual) / numpy.linalg.norm(rhs) + + assert rel_residual < 5e-2 + + +def test_continuous_wave_real_source_matches_reconstructed_source() -> None: + case = _continuous_wave_case() + accumulation_indices = numpy.arange(64 * 8, 64 * 16) + accumulation_times = (accumulation_indices + 0.5) * case.dt + accumulation_response = case.dt * numpy.sum( + numpy.exp(-1j * case.omega * accumulation_times) * numpy.cos(case.omega * accumulation_times), + ) + normalized_j_ph = case.j_ph / accumulation_response + + for snapshot in case.snapshots: + reconstructed_j = fdtd.reconstruct_real_j(normalized_j_ph, case.omega, case.dt, snapshot.step) + assert_fields_close(snapshot.j_field, reconstructed_j, atol=1e-12, rtol=1e-12) + + +@lru_cache(maxsize=1) +def _real_pulse_case() -> RealPulseCase: + spatial_shape = (5, 1, 5) + full_shape = (3, *spatial_shape) + dt = 0.25 + period_steps = 64 + total_periods = 40 + omega = 2 * numpy.pi / (period_steps * dt) + wavelength = 2 * numpy.pi / omega + total_steps = period_steps * total_periods + source_index = (1, spatial_shape[0] // 2, spatial_shape[1] // 2, spatial_shape[2] // 2) + + dxes = unit_dxes(spatial_shape) + epsilon = numpy.ones(full_shape, dtype=float) + e_field = numpy.zeros(full_shape, dtype=float) + h_field = numpy.zeros(full_shape, dtype=float) + update_e = fdtd.maxwell_e(dt=dt, dxes=dxes) + update_h = fdtd.maxwell_h(dt=dt, dxes=dxes) + + source_phasor, _delay = gaussian_packet(wl=wavelength, dwl=1.0, dt=dt, turn_on=1e-5) + aa, cc, ss = source_phasor(numpy.arange(total_steps) + 0.5) + waveform = numpy.asarray(aa * (cc + 1j * ss), dtype=complex) + scale = fdtd.real_injection_scale(waveform, omega, dt, offset_steps=0.5)[0] + + j_accumulator = numpy.zeros((1, *full_shape), dtype=complex) + target_j_ph = numpy.zeros(full_shape, dtype=complex) + target_j_ph[source_index] = 1.0 + + for step in range(total_steps): + update_e(e_field, h_field, epsilon) + + j_step = numpy.zeros_like(e_field) + j_step[source_index] = numpy.real(scale * waveform[step]) + e_field -= dt * j_step / epsilon + + fdtd.accumulate_phasor_j(j_accumulator, omega, dt, j_step, step) + + update_h(e_field, h_field) + + return RealPulseCase( + omega=omega, + dt=dt, + j_ph=j_accumulator[0], + target_j_ph=target_j_ph, + ) + + +def test_real_pulse_current_phasor_matches_target_source() -> None: + case = _real_pulse_case() + rel_err = numpy.linalg.norm(vec(case.j_ph - case.target_j_ph)) / numpy.linalg.norm(vec(case.target_j_ph)) + assert rel_err < 0.005 diff --git a/meanas/test/test_fdtd_pml.py b/meanas/test/test_fdtd_pml.py new file mode 100644 index 0000000..319260f --- /dev/null +++ b/meanas/test/test_fdtd_pml.py @@ -0,0 +1,249 @@ +from typing import Any + +import numpy +import pytest + +from .. import fdtd +from ..fdtd.base import maxwell_e, maxwell_h +from ..fdtd.pml import cpml_params, updates_with_cpml +from .utils import assert_close + + +@pytest.mark.parametrize( + ('axis', 'polarity', 'thickness', 'epsilon_eff'), + [(3, 1, 4, 1.0), (0, 0, 4, 1.0), (0, 1, 2, 1.0), (0, 1, 4, 0.0)], +) +def test_cpml_params_reject_invalid_arguments(axis: int, polarity: int, thickness: int, epsilon_eff: float) -> None: + with pytest.raises(ValueError, match='Invalid axis|Invalid polarity|wise to have a pml|epsilon_eff must be positive'): + cpml_params(axis=axis, polarity=polarity, dt=0.1, thickness=thickness, epsilon_eff=epsilon_eff) + + +def test_cpml_params_shapes_and_region() -> None: + params = cpml_params(axis=1, polarity=1, dt=0.1, thickness=3) + p0e, p1e, p2e = params['param_e'] + p0h, p1h, p2h = params['param_h'] + + assert p0e.shape == (1, 3, 1) + assert p1e.shape == (1, 3, 1) + assert p2e.shape == (1, 3, 1) + assert p0h.shape == (1, 3, 1) + assert p1h.shape == (1, 3, 1) + assert p2h.shape == (1, 3, 1) + assert params['region'][1] == slice(-3, None) + + +def test_updates_with_cpml_keeps_zero_fields_zero() -> None: + shape = (3, 4, 4, 4) + epsilon = numpy.ones(shape, dtype=float) + e = numpy.zeros(shape, dtype=float) + h = numpy.zeros(shape, dtype=float) + dxes = [[numpy.ones(4), numpy.ones(4), numpy.ones(4)] for _ in range(2)] + params: list[list[dict[str, Any] | None]] = [[None, None] for _ in range(3)] + params[0][0] = cpml_params(axis=0, polarity=-1, dt=0.1, thickness=3) + + update_e, update_h = updates_with_cpml(params, dt=0.1, dxes=dxes, epsilon=epsilon) + update_e(e, h, epsilon) + update_h(e, h) + + assert not e.any() + assert not h.any() + + +def _unit_dxes(shape: tuple[int, int, int, int]) -> list[list[numpy.ndarray]]: + return [[numpy.ones(n, dtype=float) for n in shape[1:]] for _ in range(2)] + + +def _real_field(shape: tuple[int, int, int, int], start: float) -> numpy.ndarray: + total = numpy.prod(shape, dtype=int) + return numpy.arange(start, start + total, dtype=float).reshape(shape) / total + + +def _complex_field(shape: tuple[int, int, int, int], start: float) -> numpy.ndarray: + real = _real_field(shape, start) + imag = _real_field(shape, start + real.size) + return real + 1j * imag + + +def test_updates_with_cpml_matches_base_updates_when_all_faces_disabled() -> None: + shape = (3, 4, 5, 6) + epsilon = _real_field(shape, 1.0) + 2.0 + mu = _real_field(shape, 4.0) + 1.5 + e = _real_field(shape, 10.0) + h = _real_field(shape, 100.0) + dxes = _unit_dxes(shape) + params: list[list[dict[str, Any] | None]] = [[None, None] for _ in range(3)] + + update_e_cpml, update_h_cpml = updates_with_cpml(params, dt=0.1, dxes=dxes, epsilon=epsilon) + update_e_base = maxwell_e(dt=0.1, dxes=dxes) + update_h_base = maxwell_h(dt=0.1, dxes=dxes) + + e_cpml = e.copy() + h_cpml = h.copy() + e_base = e.copy() + h_base = h.copy() + + update_e_cpml(e_cpml, h_cpml, epsilon) + update_e_base(e_base, h_base, epsilon) + update_h_cpml(e_cpml, h_cpml, mu) + update_h_base(e_base, h_base, mu) + + assert_close(e_cpml, e_base) + assert_close(h_cpml, h_base) + + +def test_updates_with_cpml_matches_base_updates_with_complex_dtype_when_all_faces_disabled() -> None: + shape = (3, 4, 5, 6) + epsilon = _real_field(shape, 1.0) + 2.0 + mu = _real_field(shape, 4.0) + 1.5 + e = _complex_field(shape, 10.0) + h = _complex_field(shape, 100.0) + dxes = _unit_dxes(shape) + params: list[list[dict[str, Any] | None]] = [[None, None] for _ in range(3)] + + update_e_cpml, update_h_cpml = updates_with_cpml(params, dt=0.1, dxes=dxes, epsilon=epsilon, dtype=complex) + update_e_base = maxwell_e(dt=0.1, dxes=dxes) + update_h_base = maxwell_h(dt=0.1, dxes=dxes) + + e_cpml = e.copy() + h_cpml = h.copy() + e_base = e.copy() + h_base = h.copy() + + update_e_cpml(e_cpml, h_cpml, epsilon) + update_e_base(e_base, h_base, epsilon) + update_h_cpml(e_cpml, h_cpml, mu) + update_h_base(e_base, h_base, mu) + + assert_close(e_cpml, e_base) + assert_close(h_cpml, h_base) + + +def test_updates_with_cpml_only_changes_the_configured_face_region() -> None: + shape = (3, 6, 6, 6) + epsilon = numpy.ones(shape, dtype=float) + mu = numpy.ones(shape, dtype=float) + e = _real_field(shape, 1.0) + h = _real_field(shape, 100.0) + dxes = _unit_dxes(shape) + thickness = 3 + + params: list[list[dict[str, Any] | None]] = [[None, None] for _ in range(3)] + params[0][0] = cpml_params(axis=0, polarity=-1, dt=0.1, thickness=thickness) + + update_e_cpml, update_h_cpml = updates_with_cpml(params, dt=0.1, dxes=dxes, epsilon=epsilon) + update_e_base = maxwell_e(dt=0.1, dxes=dxes) + update_h_base = maxwell_h(dt=0.1, dxes=dxes) + + e_cpml = e.copy() + h_cpml = h.copy() + e_base = e.copy() + h_base = h.copy() + + update_e_cpml(e_cpml, h_cpml, epsilon) + update_e_base(e_base, h_base, epsilon) + update_h_cpml(e_cpml, h_cpml, mu) + update_h_base(e_base, h_base, mu) + + e_untouched = slice(thickness, None) + h_untouched = slice(thickness, -1) + assert_close(e_cpml[:, e_untouched, :, :], e_base[:, e_untouched, :, :]) + assert_close(h_cpml[:, h_untouched, :, :], h_base[:, h_untouched, :, :]) + + changed_e = numpy.any(numpy.abs(e_cpml[:, :thickness, :, :] - e_base[:, :thickness, :, :]) > 1e-12) + changed_h = numpy.any(numpy.abs(h_cpml[:, :thickness, :, :] - h_base[:, :thickness, :, :]) > 1e-12) + assert changed_e + assert changed_h + + +def test_cpml_plane_wave_phasor_decays_monotonically_through_outgoing_pml() -> None: + dt = 0.4 + period_steps = 24 + omega = 2 * numpy.pi / (period_steps * dt) + shape = (3, 80, 1, 1) + thickness = 8 + source_x = 16 + warmup_periods = 10 + accumulation_periods = 6 + total_steps = period_steps * (warmup_periods + accumulation_periods) + + epsilon = numpy.ones(shape, dtype=float) + dxes = _unit_dxes(shape) + params: list[list[dict[str, Any] | None]] = [[None, None] for _ in range(3)] + for polarity_index, polarity in enumerate((-1, 1)): + params[0][polarity_index] = cpml_params(axis=0, polarity=polarity, dt=dt, thickness=thickness) + + update_e, update_h = updates_with_cpml(params, dt=dt, dxes=dxes, epsilon=epsilon) + + e = numpy.zeros(shape, dtype=float) + h = numpy.zeros(shape, dtype=float) + e_accumulator = numpy.zeros((1, *shape), dtype=complex) + + for step in range(total_steps): + update_e(e, h, epsilon) + + source = numpy.cos(omega * (step + 0.5) * dt) + e[1, source_x, 0, 0] -= dt * source + + if step >= period_steps * warmup_periods: + fdtd.accumulate_phasor_e(e_accumulator, omega, dt, e, step + 1) + + update_h(e, h) + + profile = numpy.abs(e_accumulator[0, 1, :, 0, 0]) + right_pml = profile[-thickness:] + interior = profile[-thickness - 6:-thickness] + interior_level = interior.mean() + + assert interior_level > 1.0 + assert right_pml[-1] < interior_level / 100 + assert profile[0] < interior_level / 100 + assert numpy.all(numpy.diff(right_pml) <= interior_level * 1e-3) + + +@pytest.mark.complete +def test_cpml_point_source_total_energy_reaches_late_time_plateau() -> None: + dt = 0.3 + period_steps = 24 + omega = 2 * numpy.pi / (period_steps * dt) + cycles = 1000 + sample_every_cycles = 50 + sample_stride = period_steps * sample_every_cycles + shape = (3, 9, 9, 9) + thickness = 3 + center = shape[1] // 2 + + epsilon = numpy.ones(shape, dtype=float) + dxes = _unit_dxes(shape) + params: list[list[dict[str, Any] | None]] = [[None, None] for _ in range(3)] + for axis in range(3): + for polarity_index, polarity in enumerate((-1, 1)): + params[axis][polarity_index] = cpml_params(axis=axis, polarity=polarity, dt=dt, thickness=thickness) + + update_e, update_h = updates_with_cpml(params, dt=dt, dxes=dxes, epsilon=epsilon) + + e = numpy.zeros(shape, dtype=float) + h = numpy.zeros(shape, dtype=float) + sampled_energies: list[float] = [] + + for step in range(period_steps * cycles): + h_before = h.copy() + update_e(e, h, epsilon) + + source = numpy.cos(omega * (step + 0.5) * dt) + e[1, center, center, center] -= dt * source + + update_h(e, h) + + if (step + 1) % sample_stride == 0: + total_energy = fdtd.energy_estep(h0=h_before, e1=e, h2=h, epsilon=epsilon, dxes=dxes).sum().real + sampled_energies.append(total_energy) + + energies = numpy.asarray(sampled_energies) + late_window = energies[-5:] + previous_window = energies[-10:-5] + late_mean = late_window.mean() + + assert energies.size == cycles // sample_every_cycles + assert late_mean > 0.1 + assert (late_window.max() - late_window.min()) / late_mean < 1e-4 + assert abs(late_mean - previous_window.mean()) / late_mean < 1e-4 diff --git a/meanas/test/test_import_fallbacks.py b/meanas/test/test_import_fallbacks.py new file mode 100644 index 0000000..e332d1b --- /dev/null +++ b/meanas/test/test_import_fallbacks.py @@ -0,0 +1,60 @@ +import builtins +import importlib +import pathlib +from types import ModuleType +from typing import Any + +import pytest +import meanas +from ..fdfd import bloch + + +def _reload(module: ModuleType) -> ModuleType: + return importlib.reload(module) + + +def _restore_reloaded(monkeypatch: pytest.MonkeyPatch, module: ModuleType) -> ModuleType: + monkeypatch.undo() + return _reload(module) + + +def test_meanas_import_survives_readme_open_failure(monkeypatch: pytest.MonkeyPatch) -> None: + expected_version = meanas.__version__ + original_open = pathlib.Path.open + + def failing_open(self: pathlib.Path, *args: Any, **kwargs: Any) -> Any: + if self.name == 'README.md': + raise FileNotFoundError('forced README failure') + return original_open(self, *args, **kwargs) + + monkeypatch.setattr(pathlib.Path, 'open', failing_open) + reloaded = _reload(meanas) + + assert reloaded.__version__ == expected_version + assert reloaded.__author__ == 'Jan Petykiewicz' + assert reloaded.__doc__ is not None + + _restore_reloaded(monkeypatch, meanas) + + +def test_bloch_reloads_with_numpy_fft_when_pyfftw_is_unavailable(monkeypatch: pytest.MonkeyPatch) -> None: + original_import = builtins.__import__ + + def fake_import( + name: str, + globals: dict[str, Any] | None = None, + locals: dict[str, Any] | None = None, + fromlist: tuple[str, ...] = (), + level: int = 0, + ) -> Any: + if name.startswith('pyfftw'): + raise ImportError('forced pyfftw failure') + return original_import(name, globals, locals, fromlist, level) + + monkeypatch.setattr(builtins, '__import__', fake_import) + reloaded = _reload(bloch) + + assert reloaded.fftn.__module__ == 'numpy.fft' + assert reloaded.ifftn.__module__ == 'numpy.fft' + + _restore_reloaded(monkeypatch, bloch) diff --git a/meanas/test/test_waveguide_2d_numerics.py b/meanas/test/test_waveguide_2d_numerics.py new file mode 100644 index 0000000..0005584 --- /dev/null +++ b/meanas/test/test_waveguide_2d_numerics.py @@ -0,0 +1,284 @@ +import numpy +from numpy.linalg import norm +from numpy.testing import assert_allclose + +from ..fdmath import vec +from ..fdfd import waveguide_2d + + +OMEGA = 1 / 1500 +GRID_SHAPE = (5, 5) +DXES_2D = [[numpy.ones(GRID_SHAPE[0]), numpy.ones(GRID_SHAPE[1])] for _ in range(2)] +DXES_2D_NONUNIFORM = [[ + numpy.array([1.0, 1.2, 0.9, 1.1, 1.3]), + numpy.array([0.8, 1.1, 1.0, 1.2, 0.9]), +] for _ in range(2)] + + +def build_asymmetric_epsilon() -> numpy.ndarray: + epsilon = numpy.ones((3, *GRID_SHAPE), dtype=float) + epsilon[:, 2, 1] = 2.0 + return vec(epsilon) + + +def build_mu_profile() -> numpy.ndarray: + return numpy.linspace(1.5, 2.2, 3 * GRID_SHAPE[0] * GRID_SHAPE[1]) + + +def test_waveguide_2d_solved_modes_are_ordered_and_low_residual() -> None: + epsilon = build_asymmetric_epsilon() + operator_e = waveguide_2d.operator_e(OMEGA, DXES_2D, epsilon) + + e_xys, wavenumbers = waveguide_2d.solve_modes( + [0, 1], + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + + assert numpy.all(numpy.diff(numpy.real(wavenumbers)) <= 0) + + for e_xy, wavenumber in zip(e_xys, wavenumbers, strict=True): + residual = norm(operator_e @ e_xy - (wavenumber ** 2) * e_xy) / norm(e_xy) + assert residual < 1e-6 + + +def test_waveguide_2d_normalized_fields_are_consistent() -> None: + epsilon = build_asymmetric_epsilon() + operator_h = waveguide_2d.operator_h(OMEGA, DXES_2D, epsilon) + + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + e_field, h_field = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + h_xy = numpy.concatenate(numpy.split(h_field, 3)[:2]) + + overlap = waveguide_2d.inner_product(e_field, h_field, DXES_2D, conj_h=True) + h_residual = norm(operator_h @ h_xy - (wavenumber ** 2) * h_xy) / norm(h_xy) + + assert abs(overlap.real - 1.0) < 1e-10 + assert abs(overlap.imag) < 1e-10 + assert waveguide_2d.e_err(e_field, wavenumber, OMEGA, DXES_2D, epsilon) < 1e-6 + assert waveguide_2d.h_err(h_field, wavenumber, OMEGA, DXES_2D, epsilon) < 1e-6 + assert h_residual < 1e-6 + + +def test_waveguide_2d_sensitivity_matches_finite_difference() -> None: + epsilon = build_asymmetric_epsilon() + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + e_field, h_field = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + sensitivity = waveguide_2d.sensitivity( + e_field, + h_field, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + + target_index = int(numpy.argmax(numpy.abs(sensitivity))) + delta = 1e-4 + epsilon_perturbed = epsilon.copy() + epsilon_perturbed[target_index] += delta + + _, perturbed_wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon_perturbed, + ) + finite_difference = (perturbed_wavenumber - wavenumber) / delta + + assert numpy.isfinite(sensitivity[target_index]) + assert numpy.isfinite(finite_difference) + assert abs(sensitivity[target_index].imag) < 1e-10 + assert abs(finite_difference.imag) < 1e-10 + + ratio = abs(sensitivity[target_index] / finite_difference) + assert sensitivity[target_index].real > 0 + assert finite_difference.real > 0 + assert 0.4 < ratio < 1.8 + + +def test_waveguide_2d_normalized_fields_h_are_finite_and_unit_normalized_with_mu() -> None: + epsilon = build_asymmetric_epsilon() + mu = build_mu_profile() + + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + _e_ref, h_ref = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + mu=mu, + ) + h_xy = numpy.concatenate(numpy.split(h_ref, 3)[:2]) + + e_field, h_field = waveguide_2d.normalized_fields_h( + h_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + mu=mu, + ) + overlap = waveguide_2d.inner_product(e_field, h_field, DXES_2D, conj_h=True) + + assert e_field.shape == (3 * GRID_SHAPE[0] * GRID_SHAPE[1],) + assert h_field.shape == (3 * GRID_SHAPE[0] * GRID_SHAPE[1],) + assert numpy.isfinite(e_field).all() + assert numpy.isfinite(h_field).all() + assert abs(overlap.real - 1.0) < 1e-10 + assert abs(overlap.imag) < 1e-10 + + +def test_waveguide_2d_helper_operators_with_mu_return_finite_outputs() -> None: + epsilon = build_asymmetric_epsilon() + mu = build_mu_profile() + + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + _e_ref, h_ref = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + mu=mu, + ) + h_xy = numpy.concatenate(numpy.split(h_ref, 3)[:2]) + n_pts = GRID_SHAPE[0] * GRID_SHAPE[1] + + operators = [ + ('exy2h', waveguide_2d.exy2h(wavenumber, OMEGA, DXES_2D, epsilon, mu), e_xy), + ('hxy2e', waveguide_2d.hxy2e(wavenumber, OMEGA, DXES_2D, epsilon, mu), h_xy), + ('hxy2h', waveguide_2d.hxy2h(wavenumber, DXES_2D, mu), h_xy), + ] + + for _name, operator, vector in operators: + result = operator @ vector + assert operator.shape == (3 * n_pts, 2 * n_pts) + assert numpy.isfinite(operator.data).all() + assert result.shape == (3 * n_pts,) + assert numpy.isfinite(result).all() + + +def test_waveguide_2d_error_helpers_with_mu_return_finite_values() -> None: + epsilon = build_asymmetric_epsilon() + mu = build_mu_profile() + + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + e_field, h_field = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + mu=mu, + ) + + h_error = waveguide_2d.h_err(h_field, wavenumber, OMEGA, DXES_2D, epsilon, mu) + e_error = waveguide_2d.e_err(e_field, wavenumber, OMEGA, DXES_2D, epsilon, mu) + + assert numpy.isfinite(h_error) + assert numpy.isfinite(e_error) + assert 0 < h_error < 0.1 + assert 0 < e_error < 2.0 + + +def test_waveguide_2d_inner_product_phase_and_conjugation_branches() -> None: + epsilon = build_asymmetric_epsilon() + mu = build_mu_profile() + + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + ) + e_field, h_field = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D, + epsilon=epsilon, + mu=mu, + ) + + overlap_no_conj = waveguide_2d.inner_product(e_field, h_field, DXES_2D, conj_h=False) + overlap_conj = waveguide_2d.inner_product(e_field, h_field, DXES_2D, conj_h=True) + overlap_phase = waveguide_2d.inner_product(e_field, h_field, DXES_2D, conj_h=True, prop_phase=0.3) + + assert numpy.isfinite(overlap_no_conj) + assert numpy.isfinite(overlap_phase) + assert abs(overlap_no_conj.real - 1.0) < 1e-10 + assert abs(overlap_no_conj.imag) < 1e-10 + assert_allclose(overlap_phase / overlap_conj, numpy.exp(-0.15j), atol=1e-12, rtol=1e-12) + + +def test_waveguide_2d_inner_product_trapezoid_branch_on_nonuniform_grid() -> None: + epsilon = build_asymmetric_epsilon() + + e_xy, wavenumber = waveguide_2d.solve_mode( + 0, + omega=OMEGA, + dxes=DXES_2D_NONUNIFORM, + epsilon=epsilon, + ) + e_field, h_field = waveguide_2d.normalized_fields_e( + e_xy, + wavenumber=wavenumber, + omega=OMEGA, + dxes=DXES_2D_NONUNIFORM, + epsilon=epsilon, + ) + + overlap_rect = waveguide_2d.inner_product(e_field, h_field, DXES_2D_NONUNIFORM, conj_h=True) + overlap_trap = waveguide_2d.inner_product( + e_field, + h_field, + DXES_2D_NONUNIFORM, + conj_h=True, + trapezoid=True, + ) + + assert numpy.isfinite(overlap_rect) + assert numpy.isfinite(overlap_trap) + assert abs(overlap_rect.imag) < 1e-10 + assert abs(overlap_trap.imag) < 1e-10 + assert abs(overlap_rect - overlap_trap) > 0.1 diff --git a/meanas/test/test_waveguide_fdtd_fdfd.py b/meanas/test/test_waveguide_fdtd_fdfd.py new file mode 100644 index 0000000..0488197 --- /dev/null +++ b/meanas/test/test_waveguide_fdtd_fdfd.py @@ -0,0 +1,803 @@ +import dataclasses +from functools import lru_cache + +import numpy +import pytest + +from .. import fdfd, fdtd +from ..fdtd.misc import gaussian_packet +from ..fdmath import vec, unvec +from ..fdfd import functional, scpml, waveguide_3d + + +pytestmark = pytest.mark.complete + + +DT = 0.25 +PERIOD_STEPS = 64 +OMEGA = 2 * numpy.pi / (PERIOD_STEPS * DT) +WAVELENGTH = 2 * numpy.pi / OMEGA +PULSE_DWL = 4.0 +CPML_THICKNESS = 3 +WARMUP_PERIODS = 9 +ACCUMULATION_PERIODS = 9 +SHAPE = (3, 25, 13, 13) +SOURCE_SLICES = (slice(4, 5), slice(None), slice(None)) +MONITOR_SLICES = (slice(18, 19), slice(None), slice(None)) +CHOSEN_VARIANT = 'base' +REAL_FIELD_SHAPE = (3, 37, 13, 13) +REAL_FIELD_SOURCE_SLICES = (slice(5, 6), slice(None), slice(None)) +REAL_FIELD_MONITOR_SLICES = (slice(30, 31), slice(None), slice(None)) +REAL_FIELD_WARMUP_PERIODS = 16 +REAL_FIELD_SOURCE_PHASE = 0.4 +REAL_FIELD_CORE_SLICES = (slice(None), slice(None), slice(4, 9), slice(4, 9)) +SCATTERING_SHAPE = (3, 35, 15, 15) +SCATTERING_SOURCE_SLICES = (slice(4, 5), slice(None), slice(None)) +SCATTERING_REFLECT_SLICES = (slice(10, 11), slice(None), slice(None)) +SCATTERING_TRANSMIT_SLICES = (slice(29, 30), slice(None), slice(None)) +SCATTERING_STEP_X = 18 +SCATTERING_WARMUP_PERIODS = 10 +SCATTERING_ACCUMULATION_PERIODS = 10 + + +@dataclasses.dataclass(frozen=True) +class WaveguideCalibrationResult: + variant: str + e_ph: numpy.ndarray + h_ph: numpy.ndarray + j_ph: numpy.ndarray + e_fdfd: numpy.ndarray + h_fdfd: numpy.ndarray + overlap_td: complex + overlap_fd: complex + flux_td: float + flux_fd: float + + @property + def overlap_rel_err(self) -> float: + return float(abs(self.overlap_td - self.overlap_fd) / abs(self.overlap_fd)) + + @property + def overlap_mag_rel_err(self) -> float: + return float(abs(abs(self.overlap_td) - abs(self.overlap_fd)) / abs(self.overlap_fd)) + + @property + def overlap_phase_deg(self) -> float: + return float(abs(numpy.degrees(numpy.angle(self.overlap_td / self.overlap_fd)))) + + @property + def flux_rel_err(self) -> float: + return float(abs(self.flux_td - self.flux_fd) / abs(self.flux_fd)) + + @property + def combined_error(self) -> float: + return self.overlap_mag_rel_err + self.flux_rel_err + + +@dataclasses.dataclass(frozen=True) +class WaveguideScatteringResult: + e_ph: numpy.ndarray + h_ph: numpy.ndarray + j_ph: numpy.ndarray + e_fdfd: numpy.ndarray + h_fdfd: numpy.ndarray + reflected_td: complex + reflected_fd: complex + transmitted_td: complex + transmitted_fd: complex + reflected_flux_td: float + reflected_flux_fd: float + transmitted_flux_td: float + transmitted_flux_fd: float + + @property + def reflected_overlap_mag_rel_err(self) -> float: + return float(abs(abs(self.reflected_td) - abs(self.reflected_fd)) / abs(self.reflected_fd)) + + @property + def transmitted_overlap_mag_rel_err(self) -> float: + return float(abs(abs(self.transmitted_td) - abs(self.transmitted_fd)) / abs(self.transmitted_fd)) + + @property + def reflected_flux_rel_err(self) -> float: + return float(abs(self.reflected_flux_td - self.reflected_flux_fd) / abs(self.reflected_flux_fd)) + + @property + def transmitted_flux_rel_err(self) -> float: + return float(abs(self.transmitted_flux_td - self.transmitted_flux_fd) / abs(self.transmitted_flux_fd)) + + +@dataclasses.dataclass(frozen=True) +class MonitorSliceSnapshot: + step: int + e_monitor: numpy.ndarray + h_monitor: numpy.ndarray + + +@dataclasses.dataclass(frozen=True) +class PulsedWaveguideCalibrationResult: + e_ph: numpy.ndarray + h_ph: numpy.ndarray + j_ph: numpy.ndarray + j_target: numpy.ndarray + e_fdfd: numpy.ndarray + h_fdfd: numpy.ndarray + overlap_td: complex + overlap_fd: complex + flux_td: float + flux_fd: float + + @property + def j_rel_err(self) -> float: + return float(numpy.linalg.norm(vec(self.j_ph - self.j_target)) / numpy.linalg.norm(vec(self.j_target))) + + @property + def overlap_rel_err(self) -> float: + return float(abs(self.overlap_td - self.overlap_fd) / abs(self.overlap_fd)) + + @property + def overlap_mag_rel_err(self) -> float: + return float(abs(abs(self.overlap_td) - abs(self.overlap_fd)) / abs(self.overlap_fd)) + + @property + def overlap_phase_deg(self) -> float: + return float(abs(numpy.degrees(numpy.angle(self.overlap_td / self.overlap_fd)))) + + @property + def flux_rel_err(self) -> float: + return float(abs(self.flux_td - self.flux_fd) / abs(self.flux_fd)) + + +@dataclasses.dataclass(frozen=True) +class RealFieldWaveguideResult: + e_fdfd: numpy.ndarray + h_fdfd: numpy.ndarray + e_mode_weight: numpy.ndarray + h_mode_weight: numpy.ndarray + e_mode: numpy.ndarray + h_mode: numpy.ndarray + snapshots: tuple[MonitorSliceSnapshot, ...] + + + + +def _build_uniform_dxes(shape: tuple[int, int, int, int]) -> list[list[numpy.ndarray]]: + return [[numpy.ones(shape[axis + 1]) for axis in range(3)] for _ in range(2)] + + +def _build_base_dxes() -> list[list[numpy.ndarray]]: + return _build_uniform_dxes(SHAPE) + + +def _build_real_field_base_dxes() -> list[list[numpy.ndarray]]: + return _build_uniform_dxes(REAL_FIELD_SHAPE) + + +def _build_stretched_dxes(base_dxes: list[list[numpy.ndarray]]) -> list[list[numpy.ndarray]]: + stretched_dxes = [[dx.copy() for dx in group] for group in base_dxes] + for axis in (0, 1, 2): + for polarity in (-1, 1): + stretched_dxes = scpml.stretch_with_scpml( + stretched_dxes, + axis=axis, + polarity=polarity, + omega=OMEGA, + epsilon_effective=1.0, + thickness=CPML_THICKNESS, + ) + return stretched_dxes + + +def _build_epsilon() -> numpy.ndarray: + epsilon = numpy.ones(SHAPE, dtype=float) + y0 = (SHAPE[2] - 3) // 2 + z0 = (SHAPE[3] - 3) // 2 + epsilon[:, :, y0:y0 + 3, z0:z0 + 3] = 12.0 + return epsilon + + +def _build_real_field_epsilon() -> numpy.ndarray: + epsilon = numpy.ones(REAL_FIELD_SHAPE, dtype=float) + y0 = (REAL_FIELD_SHAPE[2] - 3) // 2 + z0 = (REAL_FIELD_SHAPE[3] - 3) // 2 + epsilon[:, :, y0:y0 + 3, z0:z0 + 3] = 12.0 + return epsilon + + +def _build_scattering_epsilon() -> numpy.ndarray: + epsilon = numpy.ones(SCATTERING_SHAPE, dtype=float) + y0 = SCATTERING_SHAPE[2] // 2 + z0 = SCATTERING_SHAPE[3] // 2 + epsilon[:, :SCATTERING_STEP_X, y0 - 1:y0 + 2, z0 - 1:z0 + 2] = 12.0 + epsilon[:, SCATTERING_STEP_X:, y0 - 2:y0 + 3, z0 - 2:z0 + 3] = 12.0 + return epsilon + + +def _build_cpml_params() -> list[list[dict[str, numpy.ndarray | float]]]: + return [ + [fdtd.cpml_params(axis=axis, polarity=polarity, dt=DT, thickness=CPML_THICKNESS, epsilon_eff=1.0) + for polarity in (-1, 1)] + for axis in range(3) + ] + + +def _build_complex_pulse_waveform(total_steps: int) -> tuple[numpy.ndarray, complex]: + source_phasor, _delay = gaussian_packet(wl=WAVELENGTH, dwl=PULSE_DWL, dt=DT, turn_on=1e-5) + aa, cc, ss = source_phasor(numpy.arange(total_steps) + 0.5) + waveform = numpy.asarray(aa * (cc + 1j * ss), dtype=complex) + scale = fdtd.temporal_phasor_scale(waveform, OMEGA, DT, offset_steps=0.5)[0] + return waveform, scale + + +def _weighted_rel_err( + observed: numpy.ndarray, + reference: numpy.ndarray, + weight: numpy.ndarray, + ) -> float: + return float(numpy.linalg.norm((observed - reference) * weight) / numpy.linalg.norm(reference * weight)) + + +def _project_onto_mode( + observed: numpy.ndarray, + mode: numpy.ndarray, + ) -> tuple[complex, numpy.ndarray, numpy.ndarray]: + coefficient = numpy.vdot(mode, observed) / numpy.vdot(mode, mode) + guided = coefficient * mode + residual = observed - guided + return coefficient, guided, residual + + +@lru_cache(maxsize=1) +def _run_real_field_straight_waveguide_case() -> RealFieldWaveguideResult: + epsilon = _build_real_field_epsilon() + base_dxes = _build_real_field_base_dxes() + stretched_dxes = _build_stretched_dxes(base_dxes) + + source_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=REAL_FIELD_SOURCE_SLICES, + epsilon=epsilon, + ) + j_mode = waveguide_3d.compute_source( + E=source_mode['E'], + wavenumber=source_mode['wavenumber'], + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=REAL_FIELD_SOURCE_SLICES, + epsilon=epsilon, + ) + j_mode = j_mode * numpy.exp(1j * REAL_FIELD_SOURCE_PHASE) + monitor_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=REAL_FIELD_MONITOR_SLICES, + epsilon=epsilon, + ) + e_fdfd = unvec( + fdfd.solvers.generic( + J=vec(j_mode), + omega=OMEGA, + dxes=stretched_dxes, + epsilon=vec(epsilon), + matrix_solver_opts={'atol': 1e-10, 'rtol': 1e-7}, + ), + REAL_FIELD_SHAPE[1:], + ) + h_fdfd = functional.e2h(OMEGA, stretched_dxes)(e_fdfd) + + update_e, update_h = fdtd.updates_with_cpml( + cpml_params=_build_cpml_params(), + dt=DT, + dxes=base_dxes, + epsilon=epsilon, + ) + e_field = numpy.zeros_like(epsilon) + h_field = numpy.zeros_like(epsilon) + total_steps = (REAL_FIELD_WARMUP_PERIODS + 1) * PERIOD_STEPS + snapshots: list[MonitorSliceSnapshot] = [] + + for step in range(total_steps): + update_e(e_field, h_field, epsilon) + + t_half = (step + 0.5) * DT + j_real = (j_mode.real * numpy.cos(OMEGA * t_half) - j_mode.imag * numpy.sin(OMEGA * t_half)).real + e_field -= DT * j_real / epsilon + + update_h(e_field, h_field) + + if step >= total_steps - PERIOD_STEPS // 4: + snapshots.append( + MonitorSliceSnapshot( + step=step, + e_monitor=e_field[:, REAL_FIELD_MONITOR_SLICES[0], :, :].copy(), + h_monitor=h_field[:, REAL_FIELD_MONITOR_SLICES[0], :, :].copy(), + ), + ) + + return RealFieldWaveguideResult( + e_fdfd=e_fdfd[:, REAL_FIELD_MONITOR_SLICES[0], :, :], + h_fdfd=h_fdfd[:, REAL_FIELD_MONITOR_SLICES[0], :, :], + e_mode_weight=numpy.abs(monitor_mode['E'][:, REAL_FIELD_MONITOR_SLICES[0], :, :]), + h_mode_weight=numpy.abs(monitor_mode['H'][:, REAL_FIELD_MONITOR_SLICES[0], :, :]), + e_mode=monitor_mode['E'][:, REAL_FIELD_MONITOR_SLICES[0], :, :], + h_mode=monitor_mode['H'][:, REAL_FIELD_MONITOR_SLICES[0], :, :], + snapshots=tuple(snapshots), + ) + + + + +@lru_cache(maxsize=2) +def _run_straight_waveguide_case(variant: str) -> WaveguideCalibrationResult: + assert variant in ('stretched', 'base') + + epsilon = _build_epsilon() + base_dxes = _build_base_dxes() + stretched_dxes = _build_stretched_dxes(base_dxes) + mode_dxes = stretched_dxes if variant == 'stretched' else base_dxes + + source_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=mode_dxes, + axis=0, + polarity=1, + slices=SOURCE_SLICES, + epsilon=epsilon, + ) + j_mode = waveguide_3d.compute_source( + E=source_mode['E'], + wavenumber=source_mode['wavenumber'], + omega=OMEGA, + dxes=mode_dxes, + axis=0, + polarity=1, + slices=SOURCE_SLICES, + epsilon=epsilon, + ) + monitor_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=mode_dxes, + axis=0, + polarity=1, + slices=MONITOR_SLICES, + epsilon=epsilon, + ) + overlap_e = waveguide_3d.compute_overlap_e( + E=monitor_mode['E'], + wavenumber=monitor_mode['wavenumber'], + dxes=mode_dxes, + axis=0, + polarity=1, + slices=MONITOR_SLICES, + ) + + update_e, update_h = fdtd.updates_with_cpml(cpml_params=_build_cpml_params(), dt=DT, dxes=base_dxes, epsilon=epsilon) + + e_field = numpy.zeros_like(epsilon) + h_field = numpy.zeros_like(epsilon) + e_accumulator = numpy.zeros((1, *SHAPE), dtype=complex) + h_accumulator = numpy.zeros((1, *SHAPE), dtype=complex) + j_accumulator = numpy.zeros((1, *SHAPE), dtype=complex) + + warmup_steps = WARMUP_PERIODS * PERIOD_STEPS + accumulation_steps = ACCUMULATION_PERIODS * PERIOD_STEPS + for step in range(warmup_steps + accumulation_steps): + update_e(e_field, h_field, epsilon) + + t_half = (step + 0.5) * DT + j_real = (j_mode.real * numpy.cos(OMEGA * t_half) - j_mode.imag * numpy.sin(OMEGA * t_half)).real + e_field -= DT * j_real / epsilon + + if step >= warmup_steps: + fdtd.accumulate_phasor_j(j_accumulator, OMEGA, DT, j_real, step) + fdtd.accumulate_phasor_e(e_accumulator, OMEGA, DT, e_field, step + 1) + + update_h(e_field, h_field) + + if step >= warmup_steps: + fdtd.accumulate_phasor_h(h_accumulator, OMEGA, DT, h_field, step + 1) + + e_ph = e_accumulator[0] + h_ph = h_accumulator[0] + j_ph = j_accumulator[0] + + e_fdfd = unvec( + fdfd.solvers.generic( + J=vec(j_ph), + omega=OMEGA, + dxes=stretched_dxes, + epsilon=vec(epsilon), + matrix_solver_opts={'atol': 1e-10, 'rtol': 1e-7}, + ), + SHAPE[1:], + ) + h_fdfd = functional.e2h(OMEGA, stretched_dxes)(e_fdfd) + + overlap_td = complex(vec(e_ph) @ vec(overlap_e).conj()) + overlap_fd = complex(vec(e_fdfd) @ vec(overlap_e).conj()) + + poynting_td = functional.poynting_e_cross_h(stretched_dxes)(e_ph, h_ph.conj()) + poynting_fd = functional.poynting_e_cross_h(stretched_dxes)(e_fdfd, h_fdfd.conj()) + flux_td = float(0.5 * poynting_td[0, MONITOR_SLICES[0], :, :].real.sum()) + flux_fd = float(0.5 * poynting_fd[0, MONITOR_SLICES[0], :, :].real.sum()) + + return WaveguideCalibrationResult( + variant=variant, + e_ph=e_ph, + h_ph=h_ph, + j_ph=j_ph, + e_fdfd=e_fdfd, + h_fdfd=h_fdfd, + overlap_td=overlap_td, + overlap_fd=overlap_fd, + flux_td=flux_td, + flux_fd=flux_fd, + ) + + +@lru_cache(maxsize=1) +def _run_width_step_scattering_case() -> WaveguideScatteringResult: + epsilon = _build_scattering_epsilon() + base_dxes = _build_uniform_dxes(SCATTERING_SHAPE) + stretched_dxes = _build_stretched_dxes(base_dxes) + + source_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SCATTERING_SOURCE_SLICES, + epsilon=epsilon, + ) + j_mode = waveguide_3d.compute_source( + E=source_mode['E'], + wavenumber=source_mode['wavenumber'], + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SCATTERING_SOURCE_SLICES, + epsilon=epsilon, + ) + reflected_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=-1, + slices=SCATTERING_REFLECT_SLICES, + epsilon=epsilon, + ) + reflected_overlap = waveguide_3d.compute_overlap_e( + E=reflected_mode['E'], + wavenumber=reflected_mode['wavenumber'], + dxes=base_dxes, + axis=0, + polarity=-1, + slices=SCATTERING_REFLECT_SLICES, + ) + transmitted_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SCATTERING_TRANSMIT_SLICES, + epsilon=epsilon, + ) + transmitted_overlap = waveguide_3d.compute_overlap_e( + E=transmitted_mode['E'], + wavenumber=transmitted_mode['wavenumber'], + dxes=base_dxes, + axis=0, + polarity=1, + slices=SCATTERING_TRANSMIT_SLICES, + ) + + update_e, update_h = fdtd.updates_with_cpml(cpml_params=_build_cpml_params(), dt=DT, dxes=base_dxes, epsilon=epsilon) + + e_field = numpy.zeros_like(epsilon) + h_field = numpy.zeros_like(epsilon) + e_accumulator = numpy.zeros((1, *SCATTERING_SHAPE), dtype=complex) + h_accumulator = numpy.zeros((1, *SCATTERING_SHAPE), dtype=complex) + j_accumulator = numpy.zeros((1, *SCATTERING_SHAPE), dtype=complex) + + warmup_steps = SCATTERING_WARMUP_PERIODS * PERIOD_STEPS + accumulation_steps = SCATTERING_ACCUMULATION_PERIODS * PERIOD_STEPS + for step in range(warmup_steps + accumulation_steps): + update_e(e_field, h_field, epsilon) + + t_half = (step + 0.5) * DT + j_real = (j_mode.real * numpy.cos(OMEGA * t_half) - j_mode.imag * numpy.sin(OMEGA * t_half)).real + e_field -= DT * j_real / epsilon + + if step >= warmup_steps: + fdtd.accumulate_phasor_j(j_accumulator, OMEGA, DT, j_real, step) + fdtd.accumulate_phasor_e(e_accumulator, OMEGA, DT, e_field, step + 1) + + update_h(e_field, h_field) + + if step >= warmup_steps: + fdtd.accumulate_phasor_h(h_accumulator, OMEGA, DT, h_field, step + 1) + + e_ph = e_accumulator[0] + h_ph = h_accumulator[0] + j_ph = j_accumulator[0] + + e_fdfd = unvec( + fdfd.solvers.generic( + J=vec(j_ph), + omega=OMEGA, + dxes=stretched_dxes, + epsilon=vec(epsilon), + matrix_solver_opts={'atol': 1e-10, 'rtol': 1e-7}, + ), + SCATTERING_SHAPE[1:], + ) + h_fdfd = functional.e2h(OMEGA, stretched_dxes)(e_fdfd) + + reflected_td = complex(vec(e_ph) @ vec(reflected_overlap).conj()) + reflected_fd = complex(vec(e_fdfd) @ vec(reflected_overlap).conj()) + transmitted_td = complex(vec(e_ph) @ vec(transmitted_overlap).conj()) + transmitted_fd = complex(vec(e_fdfd) @ vec(transmitted_overlap).conj()) + + poynting_td = functional.poynting_e_cross_h(stretched_dxes)(e_ph, h_ph.conj()) + poynting_fd = functional.poynting_e_cross_h(stretched_dxes)(e_fdfd, h_fdfd.conj()) + reflected_flux_td = float(0.5 * poynting_td[0, SCATTERING_REFLECT_SLICES[0], :, :].real.sum()) + reflected_flux_fd = float(0.5 * poynting_fd[0, SCATTERING_REFLECT_SLICES[0], :, :].real.sum()) + transmitted_flux_td = float(0.5 * poynting_td[0, SCATTERING_TRANSMIT_SLICES[0], :, :].real.sum()) + transmitted_flux_fd = float(0.5 * poynting_fd[0, SCATTERING_TRANSMIT_SLICES[0], :, :].real.sum()) + + return WaveguideScatteringResult( + e_ph=e_ph, + h_ph=h_ph, + j_ph=j_ph, + e_fdfd=e_fdfd, + h_fdfd=h_fdfd, + reflected_td=reflected_td, + reflected_fd=reflected_fd, + transmitted_td=transmitted_td, + transmitted_fd=transmitted_fd, + reflected_flux_td=reflected_flux_td, + reflected_flux_fd=reflected_flux_fd, + transmitted_flux_td=transmitted_flux_td, + transmitted_flux_fd=transmitted_flux_fd, + ) + + +@lru_cache(maxsize=1) +def _run_pulsed_straight_waveguide_case() -> PulsedWaveguideCalibrationResult: + epsilon = _build_epsilon() + base_dxes = _build_base_dxes() + stretched_dxes = _build_stretched_dxes(base_dxes) + + source_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SOURCE_SLICES, + epsilon=epsilon, + ) + j_mode = waveguide_3d.compute_source( + E=source_mode['E'], + wavenumber=source_mode['wavenumber'], + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=SOURCE_SLICES, + epsilon=epsilon, + ) + monitor_mode = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=base_dxes, + axis=0, + polarity=1, + slices=MONITOR_SLICES, + epsilon=epsilon, + ) + overlap_e = waveguide_3d.compute_overlap_e( + E=monitor_mode['E'], + wavenumber=monitor_mode['wavenumber'], + dxes=base_dxes, + axis=0, + polarity=1, + slices=MONITOR_SLICES, + ) + + update_e, update_h = fdtd.updates_with_cpml(cpml_params=_build_cpml_params(), dt=DT, dxes=base_dxes, epsilon=epsilon, dtype=complex) + + e_field = numpy.zeros_like(epsilon, dtype=complex) + h_field = numpy.zeros_like(epsilon, dtype=complex) + e_accumulator = numpy.zeros((1, *SHAPE), dtype=complex) + h_accumulator = numpy.zeros((1, *SHAPE), dtype=complex) + j_accumulator = numpy.zeros((1, *SHAPE), dtype=complex) + + total_steps = (WARMUP_PERIODS + ACCUMULATION_PERIODS) * PERIOD_STEPS + waveform, pulse_scale = _build_complex_pulse_waveform(total_steps) + + for step in range(total_steps): + update_e(e_field, h_field, epsilon) + + j_step = pulse_scale * waveform[step] * j_mode + e_field -= DT * j_step / epsilon + + fdtd.accumulate_phasor_j(j_accumulator, OMEGA, DT, j_step, step) + fdtd.accumulate_phasor_e(e_accumulator, OMEGA, DT, e_field, step + 1) + + update_h(e_field, h_field) + + fdtd.accumulate_phasor_h(h_accumulator, OMEGA, DT, h_field, step + 1) + + e_ph = e_accumulator[0] + h_ph = h_accumulator[0] + j_ph = j_accumulator[0] + + e_fdfd = unvec( + fdfd.solvers.generic( + J=vec(j_ph), + omega=OMEGA, + dxes=stretched_dxes, + epsilon=vec(epsilon), + matrix_solver_opts={'atol': 1e-10, 'rtol': 1e-7}, + ), + SHAPE[1:], + ) + h_fdfd = functional.e2h(OMEGA, stretched_dxes)(e_fdfd) + + overlap_td = complex(vec(e_ph) @ vec(overlap_e).conj()) + overlap_fd = complex(vec(e_fdfd) @ vec(overlap_e).conj()) + + poynting_td = functional.poynting_e_cross_h(stretched_dxes)(e_ph, h_ph.conj()) + poynting_fd = functional.poynting_e_cross_h(stretched_dxes)(e_fdfd, h_fdfd.conj()) + flux_td = float(0.5 * poynting_td[0, MONITOR_SLICES[0], :, :].real.sum()) + flux_fd = float(0.5 * poynting_fd[0, MONITOR_SLICES[0], :, :].real.sum()) + + return PulsedWaveguideCalibrationResult( + e_ph=e_ph, + h_ph=h_ph, + j_ph=j_ph, + j_target=j_mode, + e_fdfd=e_fdfd, + h_fdfd=h_fdfd, + overlap_td=overlap_td, + overlap_fd=overlap_fd, + flux_td=flux_td, + flux_fd=flux_fd, + ) + + + + +def test_straight_waveguide_base_variant_outperforms_stretched_variant() -> None: + base_result = _run_straight_waveguide_case('base') + stretched_result = _run_straight_waveguide_case('stretched') + + assert base_result.variant == CHOSEN_VARIANT + assert base_result.combined_error < stretched_result.combined_error + + +def test_straight_waveguide_fdtd_fdfd_overlap_and_flux_agree() -> None: + result = _run_straight_waveguide_case(CHOSEN_VARIANT) + + assert numpy.isfinite(result.e_ph).all() + assert numpy.isfinite(result.h_ph).all() + assert numpy.isfinite(result.j_ph).all() + assert numpy.isfinite(result.e_fdfd).all() + assert numpy.isfinite(result.h_fdfd).all() + assert abs(result.overlap_td) > 0 + assert abs(result.overlap_fd) > 0 + assert abs(result.flux_td) > 0 + assert abs(result.flux_fd) > 0 + + assert result.overlap_mag_rel_err < 0.01 + assert result.flux_rel_err < 0.01 + assert result.overlap_rel_err < 0.01 + assert result.overlap_phase_deg < 0.5 + + +def test_straight_waveguide_real_snapshot_diagnostic_tracks_guided_content_and_bounded_residual() -> None: + # The phasor-based waveguide tests above are the primary FDTD/FDFD + # equivalence benchmark. This raw real-field check is intentionally stricter: + # it validates that late monitor snapshots keep the guided content close to + # the reconstructed FDFD field while the orthogonal residual stays bounded. + result = _run_real_field_straight_waveguide_case() + ranked_snapshots = sorted( + result.snapshots, + key=lambda snapshot: numpy.linalg.norm( + fdtd.reconstruct_real_e(result.e_fdfd, OMEGA, DT, snapshot.step + 1), + ), + reverse=True, + ) + + for snapshot in ranked_snapshots[:3]: + reconstructed_e = fdtd.reconstruct_real_e(result.e_fdfd, OMEGA, DT, snapshot.step + 1) + reconstructed_h = fdtd.reconstruct_real_h(result.h_fdfd, OMEGA, DT, snapshot.step + 1) + + e_rel_err = numpy.linalg.norm(snapshot.e_monitor - reconstructed_e) / numpy.linalg.norm(reconstructed_e) + h_rel_err = numpy.linalg.norm(snapshot.h_monitor - reconstructed_h) / numpy.linalg.norm(reconstructed_h) + e_core_rel_err = numpy.linalg.norm( + snapshot.e_monitor[REAL_FIELD_CORE_SLICES] - reconstructed_e[REAL_FIELD_CORE_SLICES], + ) / numpy.linalg.norm(reconstructed_e[REAL_FIELD_CORE_SLICES]) + h_core_rel_err = numpy.linalg.norm( + snapshot.h_monitor[REAL_FIELD_CORE_SLICES] - reconstructed_h[REAL_FIELD_CORE_SLICES], + ) / numpy.linalg.norm(reconstructed_h[REAL_FIELD_CORE_SLICES]) + e_weighted_rel_err = _weighted_rel_err(snapshot.e_monitor, reconstructed_e, result.e_mode_weight) + h_weighted_rel_err = _weighted_rel_err(snapshot.h_monitor, reconstructed_h, result.h_mode_weight) + e_guided_coeff, _, e_residual = _project_onto_mode(snapshot.e_monitor, result.e_mode) + e_guided_coeff_ref, _, e_residual_ref = _project_onto_mode(reconstructed_e, result.e_mode) + h_guided_coeff, _, h_residual = _project_onto_mode(snapshot.h_monitor, result.h_mode) + h_guided_coeff_ref, _, h_residual_ref = _project_onto_mode(reconstructed_h, result.h_mode) + e_guided_rel_err = abs(e_guided_coeff - e_guided_coeff_ref) / abs(e_guided_coeff_ref) + h_guided_rel_err = abs(h_guided_coeff - h_guided_coeff_ref) / abs(h_guided_coeff_ref) + e_residual_rel_err = numpy.linalg.norm(e_residual - e_residual_ref) / numpy.linalg.norm(e_residual_ref) + h_residual_rel_err = numpy.linalg.norm(h_residual - h_residual_ref) / numpy.linalg.norm(h_residual_ref) + + assert e_rel_err < 0.075 + assert h_rel_err < 0.075 + assert e_core_rel_err < 0.055 + assert h_core_rel_err < 0.055 + assert e_weighted_rel_err < 0.055 + assert h_weighted_rel_err < 0.03 + assert e_guided_rel_err < 0.04 + assert h_guided_rel_err < 0.03 + assert e_residual_rel_err < 0.115 + assert h_residual_rel_err < 0.115 + + +def test_width_step_waveguide_fdtd_fdfd_modal_powers_and_flux_agree() -> None: + result = _run_width_step_scattering_case() + + assert numpy.isfinite(result.e_ph).all() + assert numpy.isfinite(result.h_ph).all() + assert numpy.isfinite(result.j_ph).all() + assert numpy.isfinite(result.e_fdfd).all() + assert numpy.isfinite(result.h_fdfd).all() + assert abs(result.reflected_td) > 0 + assert abs(result.reflected_fd) > 0 + assert abs(result.transmitted_td) > 0 + assert abs(result.transmitted_fd) > 0 + assert abs(result.reflected_flux_td) > 0 + assert abs(result.reflected_flux_fd) > 0 + assert abs(result.transmitted_flux_td) > 0 + assert abs(result.transmitted_flux_fd) > 0 + + assert result.transmitted_overlap_mag_rel_err < 0.03 + assert result.reflected_overlap_mag_rel_err < 0.03 + assert result.transmitted_flux_rel_err < 0.01 + assert result.reflected_flux_rel_err < 0.01 + + +def test_pulsed_straight_waveguide_fdtd_fdfd_overlap_flux_and_source_agree() -> None: + result = _run_pulsed_straight_waveguide_case() + + assert numpy.isfinite(result.e_ph).all() + assert numpy.isfinite(result.h_ph).all() + assert numpy.isfinite(result.j_ph).all() + assert numpy.isfinite(result.e_fdfd).all() + assert numpy.isfinite(result.h_fdfd).all() + assert abs(result.overlap_td) > 0 + assert abs(result.overlap_fd) > 0 + assert abs(result.flux_td) > 0 + assert abs(result.flux_fd) > 0 + + assert result.j_rel_err < 1e-9 + assert result.overlap_mag_rel_err < 0.01 + assert result.flux_rel_err < 0.03 + assert result.overlap_rel_err < 0.01 + assert result.overlap_phase_deg < 0.5 diff --git a/meanas/test/test_waveguide_mode_helpers.py b/meanas/test/test_waveguide_mode_helpers.py new file mode 100644 index 0000000..d3ec7cd --- /dev/null +++ b/meanas/test/test_waveguide_mode_helpers.py @@ -0,0 +1,295 @@ +import contextlib +import io +import numpy +from numpy.linalg import norm +import pytest +import warnings + +from ..fdmath import vec, unvec +from ..fdfd import waveguide_2d, waveguide_3d, waveguide_cyl + + +OMEGA = 1 / 1500 + + +def build_waveguide_3d_mode( + *, + slice_start: int, + polarity: int, + ) -> tuple[numpy.ndarray, list[list[numpy.ndarray]], tuple[slice, slice, slice], waveguide_3d.Waveguide3DMode]: + epsilon = numpy.ones((3, 5, 5, 1), dtype=float) + dxes = [[numpy.ones(5), numpy.ones(5), numpy.ones(1)] for _ in range(2)] + slices = (slice(slice_start, slice_start + 1), slice(None), slice(None)) + result = waveguide_3d.solve_mode( + 0, + omega=OMEGA, + dxes=dxes, + axis=0, + polarity=polarity, + slices=slices, + epsilon=epsilon, + ) + return epsilon, dxes, slices, result + + +def build_waveguide_cyl_fixture( + *, + nonuniform: bool = False, + ) -> tuple[list[list[numpy.ndarray]], numpy.ndarray, float]: + if nonuniform: + dxes = [ + [numpy.array([1.0, 1.5, 1.2, 0.8, 1.1]), numpy.ones(5)], + [numpy.array([0.9, 1.4, 1.0, 0.7, 1.2]), numpy.ones(5)], + ] + else: + dxes = [[numpy.ones(5), numpy.ones(5)] for _ in range(2)] + epsilon = vec(numpy.ones((3, 5, 5), dtype=float)) + return dxes, epsilon, 10.0 + + +def test_waveguide_3d_solve_mode_and_expand_e_are_phase_consistent() -> None: + epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=0, polarity=1) + axis = 0 + polarity = 1 + expanded = waveguide_3d.expand_e( + E=result['E'], + wavenumber=result['wavenumber'], + dxes=dxes, + axis=axis, + polarity=polarity, + slices=slices, + ) + + dx_prop = 0.5 * numpy.array([dx[2][slices[2]] for dx in dxes]).sum() + expected_wavenumber = 2 / dx_prop * numpy.arcsin(result['wavenumber_2d'] * dx_prop / 2) + solved_slice = (slice(None), *slices) + + assert result['E'].shape == epsilon.shape + assert result['H'].shape == epsilon.shape + assert numpy.isfinite(result['E']).all() + assert numpy.isfinite(result['H']).all() + assert abs(result['wavenumber'] - expected_wavenumber) < 1e-12 + assert numpy.allclose(expanded[solved_slice], result['E'][solved_slice]) + + component, _x, y_index, z_index = numpy.unravel_index( + numpy.abs(result['E']).argmax(), + result['E'].shape, + ) + values = expanded[component, :, y_index, z_index] + ratios = values[1:] / values[:-1] + expected_ratio = numpy.exp(-1j * result['wavenumber']) + + numpy.testing.assert_allclose(ratios, expected_ratio, rtol=1e-6, atol=1e-9) + + +@pytest.mark.parametrize( + ('polarity', 'expected_range'), + [(1, (0, 1)), (-1, (3, 4))], + ) +def test_waveguide_3d_compute_overlap_e_uses_adjacent_window( + polarity: int, + expected_range: tuple[int, int], + ) -> None: + _epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=2, polarity=polarity) + + with warnings.catch_warnings(record=True) as caught: + overlap = waveguide_3d.compute_overlap_e( + E=result['E'], + wavenumber=result['wavenumber'], + dxes=dxes, + axis=0, + polarity=polarity, + slices=slices, + ) + + nonzero = numpy.argwhere(numpy.abs(overlap) > 0) + + assert not caught + assert numpy.isfinite(overlap).all() + assert nonzero[:, 1].min() == expected_range[0] + assert nonzero[:, 1].max() == expected_range[1] + + +@pytest.mark.parametrize( + ('polarity', 'slice_start', 'expected_index'), + [(1, 1, 0), (-1, 3, 4)], + ) +def test_waveguide_3d_compute_overlap_e_warns_when_window_is_clipped( + polarity: int, + slice_start: int, + expected_index: int, + ) -> None: + _epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=slice_start, polarity=polarity) + + with pytest.warns(RuntimeWarning, match='clipped'): + overlap = waveguide_3d.compute_overlap_e( + E=result['E'], + wavenumber=result['wavenumber'], + dxes=dxes, + axis=0, + polarity=polarity, + slices=slices, + ) + + nonzero = numpy.argwhere(numpy.abs(overlap) > 0) + + assert numpy.isfinite(overlap).all() + assert nonzero[:, 1].min() == expected_index + assert nonzero[:, 1].max() == expected_index + + +@pytest.mark.parametrize( + ('polarity', 'slice_start'), + [(1, 0), (-1, 4)], + ) +def test_waveguide_3d_compute_overlap_e_rejects_empty_overlap_window( + polarity: int, + slice_start: int, + ) -> None: + _epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=slice_start, polarity=polarity) + + with pytest.raises(ValueError, match='outside the domain'): + waveguide_3d.compute_overlap_e( + E=result['E'], + wavenumber=result['wavenumber'], + dxes=dxes, + axis=0, + polarity=polarity, + slices=slices, + ) + + +def test_waveguide_3d_compute_overlap_e_rejects_zero_support_window() -> None: + _epsilon, dxes, slices, result = build_waveguide_3d_mode(slice_start=2, polarity=1) + + with pytest.raises(ValueError, match='no overlap field support'): + waveguide_3d.compute_overlap_e( + E=numpy.zeros_like(result['E']), + wavenumber=result['wavenumber'], + dxes=dxes, + axis=0, + polarity=1, + slices=slices, + ) + + +def test_waveguide_cyl_solved_modes_are_ordered_and_low_residual() -> None: + dxes, epsilon, rmin = build_waveguide_cyl_fixture() + + e_xys, angular_wavenumbers = waveguide_cyl.solve_modes( + [0, 1], + omega=OMEGA, + dxes=dxes, + epsilon=epsilon, + rmin=rmin, + ) + operator = waveguide_cyl.cylindrical_operator(OMEGA, dxes, epsilon, rmin=rmin) + + assert numpy.all(numpy.diff(numpy.real(angular_wavenumbers)) <= 0) + + for e_xy, angular_wavenumber in zip(e_xys, angular_wavenumbers, strict=True): + eigenvalue = (angular_wavenumber / rmin) ** 2 + residual = norm(operator @ e_xy - eigenvalue * e_xy) / norm(e_xy) + assert residual < 1e-6 + + +def test_waveguide_cyl_linear_wavenumbers_are_finite_and_ordered() -> None: + dxes, epsilon, rmin = build_waveguide_cyl_fixture() + + e_xys, angular_wavenumbers = waveguide_cyl.solve_modes( + [0, 1], + omega=OMEGA, + dxes=dxes, + epsilon=epsilon, + rmin=10.0, + ) + linear_wavenumbers = waveguide_cyl.linear_wavenumbers( + e_xys, + angular_wavenumbers, + epsilon=epsilon, + dxes=dxes, + rmin=rmin, + ) + + assert numpy.isfinite(linear_wavenumbers).all() + assert numpy.all(numpy.real(linear_wavenumbers) > 0) + assert numpy.all(numpy.diff(numpy.real(linear_wavenumbers)) <= 0) + + +def test_waveguide_cyl_dxes2t_matches_expected_radius_scaling() -> None: + dxes, _epsilon, rmin = build_waveguide_cyl_fixture(nonuniform=True) + Ta, Tb = waveguide_cyl.dxes2T(dxes, rmin) + + ta = (rmin + numpy.cumsum(dxes[0][0])) / rmin + tb = (rmin + dxes[0][0] / 2 + numpy.cumsum(dxes[1][0])) / rmin + + numpy.testing.assert_allclose(Ta.diagonal(), numpy.repeat(ta, dxes[0][1].size)) + numpy.testing.assert_allclose(Tb.diagonal(), numpy.repeat(tb, dxes[1][1].size)) + + +def test_waveguide_cyl_exy2e_and_exy2h_return_finite_full_fields() -> None: + dxes, epsilon, rmin = build_waveguide_cyl_fixture() + mu = vec(2 * numpy.ones((3, 5, 5), dtype=float)) + e_xy, angular_wavenumber = waveguide_cyl.solve_mode( + 0, + omega=OMEGA, + dxes=dxes, + epsilon=epsilon, + rmin=rmin, + ) + + e_field = waveguide_cyl.exy2e( + angular_wavenumber=angular_wavenumber, + omega=OMEGA, + dxes=dxes, + rmin=rmin, + epsilon=epsilon, + ) @ e_xy + h_field = waveguide_cyl.exy2h( + angular_wavenumber=angular_wavenumber, + omega=OMEGA, + dxes=dxes, + rmin=rmin, + epsilon=epsilon, + mu=mu, + ) @ e_xy + + assert e_field.shape == (3 * 25,) + assert h_field.shape == (3 * 25,) + assert numpy.isfinite(e_field).all() + assert numpy.isfinite(h_field).all() + assert unvec(e_field, (5, 5)).shape == (3, 5, 5) + assert unvec(h_field, (5, 5)).shape == (3, 5, 5) + + +@pytest.mark.parametrize('use_mu', [False, True]) +def test_waveguide_cyl_normalized_fields_are_unit_norm_and_silent(use_mu: bool) -> None: + dxes, epsilon, rmin = build_waveguide_cyl_fixture() + mu = vec(2 * numpy.ones((3, 5, 5), dtype=float)) if use_mu else None + e_xy, angular_wavenumber = waveguide_cyl.solve_mode( + 0, + omega=OMEGA, + dxes=dxes, + epsilon=epsilon, + rmin=rmin, + ) + + output = io.StringIO() + with contextlib.redirect_stdout(output): + e_field, h_field = waveguide_cyl.normalized_fields_e( + e_xy, + angular_wavenumber=angular_wavenumber, + omega=OMEGA, + dxes=dxes, + rmin=rmin, + epsilon=epsilon, + mu=mu, + ) + + overlap = waveguide_2d.inner_product(e_field, h_field, dxes, conj_h=True) + + assert output.getvalue() == '' + assert numpy.isfinite(e_field).all() + assert numpy.isfinite(h_field).all() + assert abs(overlap.real - 1.0) < 1e-10 + assert abs(overlap.imag) < 1e-10 diff --git a/meanas/test/utils.py b/meanas/test/utils.py index 00ed3f1..62afaf0 100644 --- a/meanas/test/utils.py +++ b/meanas/test/utils.py @@ -1,31 +1,33 @@ -from typing import Any - import numpy from numpy.typing import NDArray +from numpy.typing import ArrayLike -PRNG = numpy.random.RandomState(12345) +def make_prng(seed: int = 12345) -> numpy.random.RandomState: + return numpy.random.RandomState(seed) def assert_fields_close( x: NDArray, y: NDArray, - *args: Any, - **kwargs: Any, - ) -> None: - numpy.testing.assert_allclose( - x, y, verbose=False, # type: ignore - err_msg='Fields did not match:\n{}\n{}'.format(numpy.moveaxis(x, -1, 0), - numpy.moveaxis(y, -1, 0)), *args, **kwargs, + ) -> None: + x_disp = numpy.moveaxis(x, -1, 0) + y_disp = numpy.moveaxis(y, -1, 0) + numpy.testing.assert_allclose( + x, # type: ignore + y, # type: ignore + *args, + verbose=False, + err_msg=f'Fields did not match:\n{x_disp}\n{y_disp}', + **kwargs, ) def assert_close( - x: NDArray, - y: NDArray, - *args: Any, - **kwargs: Any, + x: ArrayLike, + y: ArrayLike, + *args, + **kwargs, ) -> None: - numpy.testing.assert_allclose(x, y, *args, **kwargs) - + numpy.testing.assert_allclose(numpy.asarray(x), numpy.asarray(y), *args, **kwargs) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..379af9b --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,89 @@ +site_name: meanas +site_description: Electromagnetic simulation tools +site_url: !ENV [DOCS_SITE_URL, ""] +repo_url: https://mpxd.net/code/jan/meanas +repo_name: meanas +docs_dir: docs +site_dir: site +strict: false + +theme: + name: material + font: false + palette: + - scheme: slate + primary: blue grey + accent: cyan + toggle: + icon: material/weather-sunny + name: Switch to light mode + - scheme: default + primary: teal + accent: indigo + toggle: + icon: material/weather-night + name: Switch to dark mode + features: + - navigation.indexes + - navigation.sections + - navigation.top + - content.code.copy + - toc.follow + +nav: + - Home: index.md + - API: + - Overview: api/index.md + - meanas: api/meanas.md + - eigensolvers: api/eigensolvers.md + - fdfd: api/fdfd.md + - waveguides: api/waveguides.md + - fdtd: api/fdtd.md + - fdmath: api/fdmath.md + +plugins: + - search + - mkdocstrings: + handlers: + python: + paths: + - !ENV [MKDOCSTRINGS_PYTHON_PATH, "."] + options: + show_root_heading: true + show_root_toc_entry: false + show_source: false + show_signature_annotations: true + show_symbol_type_heading: true + show_symbol_type_toc: true + members_order: source + separate_signature: true + merge_init_into_class: true + docstring_style: google + - print-site + +markdown_extensions: + - admonition + - attr_list + - md_in_html + - tables + - toc: + permalink: true + - pymdownx.arithmatex: + generic: true + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + +extra_css: + - stylesheets/extra.css + +extra_javascript: + - javascripts/mathjax.js + - assets/vendor/mathjax/startup.js + +watch: + - meanas diff --git a/pdoc_templates/config.mako b/pdoc_templates/config.mako deleted file mode 100644 index 93cf716..0000000 --- a/pdoc_templates/config.mako +++ /dev/null @@ -1,47 +0,0 @@ -<%! - # Template configuration. Copy over in your template directory - # (used with --template-dir) and adapt as required. - html_lang = 'en' - show_inherited_members = False - extract_module_toc_into_sidebar = True - list_class_variables_in_index = True - sort_identifiers = True - show_type_annotations = True - - # Show collapsed source code block next to each item. - # Disabling this can improve rendering speed of large modules. - show_source_code = True - - # If set, format links to objects in online source code repository - # according to this template. Supported keywords for interpolation - # are: commit, path, start_line, end_line. - #git_link_template = 'https://github.com/USER/PROJECT/blob/{commit}/{path}#L{start_line}-L{end_line}' - #git_link_template = 'https://gitlab.com/USER/PROJECT/blob/{commit}/{path}#L{start_line}-L{end_line}' - #git_link_template = 'https://bitbucket.org/USER/PROJECT/src/{commit}/{path}#lines-{start_line}:{end_line}' - #git_link_template = 'https://CGIT_HOSTNAME/PROJECT/tree/{path}?id={commit}#n{start_line}' - #git_link_template = None - git_link_template = 'https://mpxd.net/code/jan/meanas/src/commit/{commit}/{path}#L{start_line}-L{end_line}' - - # A prefix to use for every HTML hyperlink in the generated documentation. - # No prefix results in all links being relative. - link_prefix = '' - - # Enable syntax highlighting for code/source blocks by including Highlight.js - syntax_highlighting = True - - # Set the style keyword such as 'atom-one-light' or 'github-gist' - # Options: https://github.com/highlightjs/highlight.js/tree/master/src/styles - # Demo: https://highlightjs.org/static/demo/ - hljs_style = 'github' - - # If set, insert Google Analytics tracking code. Value is GA - # tracking id (UA-XXXXXX-Y). - google_analytics = '' - - # If set, render LaTeX math syntax within \(...\) (inline equations), - # or within \[...\] or $$...$$ or `.. math::` (block equations) - # as nicely-formatted math formulas using MathJax. - # Note: in Python docstrings, either all backslashes need to be escaped (\\) - # or you need to use raw r-strings. - latex_math = True -%> diff --git a/pdoc_templates/css.mako b/pdoc_templates/css.mako deleted file mode 100644 index 39a77ed..0000000 --- a/pdoc_templates/css.mako +++ /dev/null @@ -1,389 +0,0 @@ -<%! - from pdoc.html_helpers import minify_css -%> - -<%def name="mobile()" filter="minify_css"> - .flex { - display: flex !important; - } - - body { - line-height: 1.5em; - background: black; - color: #DDD; - } - - #content { - padding: 20px; - } - - #sidebar { - padding: 30px; - overflow: hidden; - } - - .http-server-breadcrumbs { - font-size: 130%; - margin: 0 0 15px 0; - } - - #footer { - font-size: .75em; - padding: 5px 30px; - border-top: 1px solid #ddd; - text-align: right; - } - #footer p { - margin: 0 0 0 1em; - display: inline-block; - } - #footer p:last-child { - margin-right: 30px; - } - - h1, h2, h3, h4, h5 { - font-weight: 300; - } - h1 { - font-size: 2.5em; - line-height: 1.1em; - } - h2 { - font-size: 1.75em; - margin: 1em 0 .50em 0; - } - h3 { - font-size: 1.4em; - margin: 25px 0 10px 0; - } - h4 { - margin: 0; - font-size: 105%; - } - - a { - color: #999; - text-decoration: none; - transition: color .3s ease-in-out; - } - a:hover { - color: #18d; - } - - .title code { - font-weight: bold; - } - h2[id^="header-"] { - margin-top: 2em; - } - .ident { - color: #7ff; - } - - pre code { - background: transparent; - font-size: .8em; - line-height: 1.4em; - } - code { - background: #0d0d0e; - padding: 1px 4px; - overflow-wrap: break-word; - } - h1 code { background: transparent } - - pre { - background: #111; - border: 0; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; - margin: 1em 0; - padding: 1ex; - } - - #http-server-module-list { - display: flex; - flex-flow: column; - } - #http-server-module-list div { - display: flex; - } - #http-server-module-list dt { - min-width: 10%; - } - #http-server-module-list p { - margin-top: 0; - } - - .toc ul, - #index { - list-style-type: none; - margin: 0; - padding: 0; - } - #index code { - background: transparent; - } - #index h3 { - border-bottom: 1px solid #ddd; - } - #index ul { - padding: 0; - } - #index h4 { - font-weight: bold; - } - #index h4 + ul { - margin-bottom:.6em; - } - /* Make TOC lists have 2+ columns when viewport is wide enough. - Assuming ~20-character identifiers and ~30% wide sidebar. */ - @media (min-width: 200ex) { #index .two-column { column-count: 2 } } - @media (min-width: 300ex) { #index .two-column { column-count: 3 } } - - dl { - margin-bottom: 2em; - } - dl dl:last-child { - margin-bottom: 4em; - } - dd { - margin: 0 0 1em 3em; - } - #header-classes + dl > dd { - margin-bottom: 3em; - } - dd dd { - margin-left: 2em; - } - dd p { - margin: 10px 0; - } - .name { - background: #111; - font-weight: bold; - font-size: .85em; - padding: 5px 10px; - display: inline-block; - min-width: 40%; - } - .name:hover { - background: #101010; - } - .name > span:first-child { - white-space: nowrap; - } - .name.class > span:nth-child(2) { - margin-left: .4em; - } - .inherited { - color: #777; - border-left: 5px solid #eee; - padding-left: 1em; - } - .inheritance em { - font-style: normal; - font-weight: bold; - } - - /* Docstrings titles, e.g. in numpydoc format */ - .desc h2 { - font-weight: 400; - font-size: 1.25em; - } - .desc h3 { - font-size: 1em; - } - .desc dt code { - background: inherit; /* Don't grey-back parameters */ - } - - .source summary, - .git-link-div { - color: #aaa; - text-align: right; - font-weight: 400; - font-size: .8em; - text-transform: uppercase; - } - .source summary > * { - white-space: nowrap; - cursor: pointer; - } - .git-link { - color: inherit; - margin-left: 1em; - } - .source pre { - max-height: 500px; - overflow: auto; - margin: 0; - } - .source pre code { - font-size: 12px; - overflow: visible; - } - .hlist { - list-style: none; - } - .hlist li { - display: inline; - } - .hlist li:after { - content: ',\2002'; - } - .hlist li:last-child:after { - content: none; - } - .hlist .hlist { - display: inline; - padding-left: 1em; - } - - img { - max-width: 100%; - } - - .admonition { - padding: .1em .5em; - margin-bottom: 1em; - } - .admonition-title { - font-weight: bold; - } - .admonition.note, - .admonition.info, - .admonition.important { - background: #610; - } - .admonition.todo, - .admonition.versionadded, - .admonition.tip, - .admonition.hint { - background: #202; - } - .admonition.warning, - .admonition.versionchanged, - .admonition.deprecated { - background: #02b; - } - .admonition.error, - .admonition.danger, - .admonition.caution { - background: darkpink; - } - - -<%def name="desktop()" filter="minify_css"> - @media screen and (min-width: 700px) { - #sidebar { - width: 30%; - } - #content { - width: 70%; - max-width: 100ch; - padding: 3em 4em; - border-left: 1px solid #ddd; - } - pre code { - font-size: 1em; - } - .item .name { - font-size: 1em; - } - main { - display: flex; - flex-direction: row-reverse; - justify-content: flex-end; - } - .toc ul ul, - #index ul { - padding-left: 1.5em; - } - .toc > ul > li { - margin-top: .5em; - } - } - - -<%def name="print()" filter="minify_css"> -@media print { - #sidebar h1 { - page-break-before: always; - } - .source { - display: none; - } -} -@media print { - * { - background: transparent !important; - color: #000 !important; /* Black prints faster: h5bp.com/s */ - box-shadow: none !important; - text-shadow: none !important; - } - - a[href]:after { - content: " (" attr(href) ")"; - font-size: 90%; - } - /* Internal, documentation links, recognized by having a title, - don't need the URL explicity stated. */ - a[href][title]:after { - content: none; - } - - abbr[title]:after { - content: " (" attr(title) ")"; - } - - /* - * Don't show links for images, or javascript/internal links - */ - - .ir a:after, - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; - } - - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - - thead { - display: table-header-group; /* h5bp.com/t */ - } - - tr, - img { - page-break-inside: avoid; - } - - img { - max-width: 100% !important; - } - - @page { - margin: 0.5cm; - } - - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - page-break-after: avoid; - } -} - diff --git a/pdoc_templates/html.mako b/pdoc_templates/html.mako deleted file mode 100644 index 6b3326f..0000000 --- a/pdoc_templates/html.mako +++ /dev/null @@ -1,445 +0,0 @@ -<% - import os - - import pdoc - from pdoc.html_helpers import extract_toc, glimpse, to_html as _to_html, format_git_link, _md, to_markdown - - from markdown.inlinepatterns import InlineProcessor - from markdown.util import AtomicString, etree - - - def link(d, name=None, fmt='{}'): - name = fmt.format(name or d.qualname + ('()' if isinstance(d, pdoc.Function) else '')) - if not isinstance(d, pdoc.Doc) or isinstance(d, pdoc.External) and not external_links: - return name - url = d.url(relative_to=module, link_prefix=link_prefix, - top_ancestor=not show_inherited_members) - return '{}'.format(d.refname, url, name) - - - # Altered latex delimeters (allow inline $...$, wrap in ) - class _MathPattern(InlineProcessor): - NAME = 'pdoc-math' - PATTERN = r'(? - -<%def name="ident(name)">${name} - -<%def name="show_source(d)"> - % if (show_source_code or git_link_template) and d.source and d.obj is not getattr(d.inherits, 'obj', None): - <% git_link = format_git_link(git_link_template, d) %> - % if show_source_code: -

- - Expand source code - % if git_link: - Browse git - %endif - -
${d.source | h}
-
- % elif git_link: - - %endif - %endif - - -<%def name="show_desc(d, short=False)"> - <% - inherits = ' inherited' if d.inherits else '' - docstring = glimpse(d.docstring) if short or inherits else d.docstring - %> - % if d.inherits: -

- Inherited from: - % if hasattr(d.inherits, 'cls'): - ${link(d.inherits.cls)}.${link(d.inherits, d.name)} - % else: - ${link(d.inherits)} - % endif -

- % endif -
${docstring | to_html}
- % if not isinstance(d, pdoc.Module): - ${show_source(d)} - % endif - - -<%def name="show_module_list(modules)"> -

Python module list

- -% if not modules: -

No modules found.

-% else: -
- % for name, desc in modules: -
-
${name}
-
${desc | glimpse, to_html}
-
- % endfor -
-% endif - - -<%def name="show_column_list(items)"> - <% - two_column = len(items) >= 6 and all(len(i.name) < 20 for i in items) - %> -
    - % for item in items: -
  • ${link(item, item.name)}
  • - % endfor -
- - -<%def name="show_module(module)"> - <% - variables = module.variables(sort=sort_identifiers) - classes = module.classes(sort=sort_identifiers) - functions = module.functions(sort=sort_identifiers) - submodules = module.submodules() - %> - - <%def name="show_func(f)"> -
- <% - params = ', '.join(f.params(annotate=show_type_annotations, link=link)) - returns = show_type_annotations and f.return_annotation(link=link) or '' - if returns: - returns = ' ->\N{NBSP}' + returns - %> - ${f.funcdef()} ${ident(f.name)}(${params})${returns} -
-
${show_desc(f)}
- - -
- % if http_server: - - % endif -

${'Namespace' if module.is_namespace else 'Module'} ${module.name}

-
- -
- ${module.docstring | to_html} - ${show_source(module)} -
- -
- % if submodules: -

Sub-modules

-
- % for m in submodules: -
${link(m)}
-
${show_desc(m, short=True)}
- % endfor -
- % endif -
- -
- % if variables: -

Global variables

-
- % for v in variables: -
var ${ident(v.name)}
-
${show_desc(v)}
- % endfor -
- % endif -
- -
- % if functions: -

Functions

-
- % for f in functions: - ${show_func(f)} - % endfor -
- % endif -
- -
- % if classes: -

Classes

-
- % for c in classes: - <% - class_vars = c.class_variables(show_inherited_members, sort=sort_identifiers) - smethods = c.functions(show_inherited_members, sort=sort_identifiers) - inst_vars = c.instance_variables(show_inherited_members, sort=sort_identifiers) - methods = c.methods(show_inherited_members, sort=sort_identifiers) - mro = c.mro() - subclasses = c.subclasses() - params = ', '.join(c.params(annotate=show_type_annotations, link=link)) - %> -
- class ${ident(c.name)} - % if params: - (${params}) - % endif -
- -
${show_desc(c)} - - % if mro: -

Ancestors

-
    - % for cls in mro: -
  • ${link(cls)}
  • - % endfor -
- %endif - - % if subclasses: -

Subclasses

-
    - % for sub in subclasses: -
  • ${link(sub)}
  • - % endfor -
- % endif - % if class_vars: -

Class variables

-
- % for v in class_vars: -
var ${ident(v.name)}
-
${show_desc(v)}
- % endfor -
- % endif - % if smethods: -

Static methods

-
- % for f in smethods: - ${show_func(f)} - % endfor -
- % endif - % if inst_vars: -

Instance variables

-
- % for v in inst_vars: -
var ${ident(v.name)}
-
${show_desc(v)}
- % endfor -
- % endif - % if methods: -

Methods

-
- % for f in methods: - ${show_func(f)} - % endfor -
- % endif - - % if not show_inherited_members: - <% - members = c.inherited_members() - %> - % if members: -

Inherited members

-
    - % for cls, mems in members: -
  • ${link(cls)}: -
      - % for m in mems: -
    • ${link(m, name=m.name)}
    • - % endfor -
    - -
  • - % endfor -
- % endif - % endif - -
- % endfor -
- % endif -
- - -<%def name="module_index(module)"> - <% - variables = module.variables(sort=sort_identifiers) - classes = module.classes(sort=sort_identifiers) - functions = module.functions(sort=sort_identifiers) - submodules = module.submodules() - supermodule = module.supermodule - %> - - - - - - - - - - -<% - module_list = 'modules' in context.keys() # Whether we're showing module list in server mode -%> - - % if module_list: - Python module list - - % else: - ${module.name} API documentation - - % endif - - - - % if syntax_highlighting: - - %endif - - <%namespace name="css" file="css.mako" /> - - - - - % if google_analytics: - - % endif - - <%include file="head.mako"/> - - -
- % if module_list: -
- ${show_module_list(modules)} -
- % else: -
- ${show_module(module)} -
- ${module_index(module)} - % endif -
- - - -% if syntax_highlighting: - - -% endif - -% if http_server and module: ## Auto-reload on file change in dev mode - -% endif - - diff --git a/pdoc_templates/html_helpers.py b/pdoc_templates/html_helpers.py deleted file mode 100644 index 5e58405..0000000 --- a/pdoc_templates/html_helpers.py +++ /dev/null @@ -1,539 +0,0 @@ -""" -Helper functions for HTML output. -""" -import inspect -import os -import re -import subprocess -import traceback -from functools import partial, lru_cache -from typing import Callable, Match -from warnings import warn - -import markdown -from markdown.inlinepatterns import InlineProcessor -from markdown.util import AtomicString, etree - -import pdoc - - -@lru_cache() -def minify_css(css: str, - _whitespace=partial(re.compile(r'\s*([,{:;}])\s*').sub, r'\1'), - _comments=partial(re.compile(r'/\*.*?\*/', flags=re.DOTALL).sub, ''), - _trailing_semicolon=partial(re.compile(r';\s*}').sub, '}')): - """ - Minify CSS by removing extraneous whitespace, comments, and trailing semicolons. - """ - return _trailing_semicolon(_whitespace(_comments(css))).strip() - - -def minify_html(html: str, - _minify=partial( - re.compile(r'(.*?)()|(.*)', re.IGNORECASE | re.DOTALL).sub, - lambda m, _norm_space=partial(re.compile(r'\s\s+').sub, '\n'): ( - _norm_space(m.group(1) or '') + - (m.group(2) or '') + - _norm_space(m.group(3) or '')))): - """ - Minify HTML by replacing all consecutive whitespace with a single space - (or newline) character, except inside `
` tags.
-    """
-    return _minify(html)
-
-
-def glimpse(text: str, max_length=153, *, paragraph=True,
-            _split_paragraph=partial(re.compile(r'\s*\n\s*\n\s*').split, maxsplit=1),
-            _trim_last_word=partial(re.compile(r'\S+$').sub, ''),
-            _remove_titles=partial(re.compile(r'^(#+|-{4,}|={4,})', re.MULTILINE).sub, ' ')):
-    """
-    Returns a short excerpt (e.g. first paragraph) of text.
-    If `paragraph` is True, the first paragraph will be returned,
-    but never longer than `max_length` characters.
-    """
-    text = text.lstrip()
-    if paragraph:
-        text, *rest = _split_paragraph(text)
-        if rest:
-            text = text.rstrip('.')
-            text += ' …'
-        text = _remove_titles(text).strip()
-
-    if len(text) > max_length:
-        text = _trim_last_word(text[:max_length - 2])
-        if not text.endswith('.') or not paragraph:
-            text = text.rstrip('. ') + ' …'
-    return text
-
-
-_md = markdown.Markdown(
-    output_format='html5',
-    extensions=[
-        "markdown.extensions.abbr",
-        "markdown.extensions.attr_list",
-        "markdown.extensions.def_list",
-        "markdown.extensions.fenced_code",
-        "markdown.extensions.footnotes",
-        "markdown.extensions.tables",
-        "markdown.extensions.admonition",
-        "markdown.extensions.smarty",
-        "markdown.extensions.toc",
-    ],
-    extension_configs={
-        "markdown.extensions.smarty": dict(
-            smart_dashes=True,
-            smart_ellipses=True,
-            smart_quotes=False,
-            smart_angled_quotes=False,
-        ),
-    },
-)
-
-
-class _ToMarkdown:
-    """
-    This class serves as a namespace for methods converting common
-    documentation formats into markdown our Python-Markdown with
-    addons can ingest.
-
-    If debugging regexs (I can't imagine why that would be necessary
-    — they are all perfect!) an insta-preview tool such as RegEx101.com
-    will come in handy.
-    """
-    @staticmethod
-    def _deflist(name, type, desc,
-                 # Wraps any identifiers and string literals in parameter type spec
-                 # in backticks while skipping common "stopwords" such as 'or', 'of',
-                 # 'optional' ... See §4 Parameters:
-                 # https://numpydoc.readthedocs.io/en/latest/format.html#sections
-                 _type_parts=partial(
-                     re.compile(r'[\w.\'"]+').sub,
-                     lambda m: ('{}' if m.group(0) in ('of', 'or', 'default', 'optional') else
-                                '`{}`').format(m.group(0)))):
-        """
-        Returns `name`, `type`, and `desc` formatted as a
-        Python-Markdown definition list entry. See also:
-        https://python-markdown.github.io/extensions/definition_lists/
-        """
-        type = _type_parts(type or '')
-        desc = desc or ' '
-        assert _ToMarkdown._is_indented_4_spaces(desc)
-        assert name or type
-        ret = ""
-        if name:
-            ret += '**`{}`**'.format(name)
-        if type:
-            ret += ' : {}'.format(type) if ret else type
-        ret += '\n:   {}\n\n'.format(desc)
-        return ret
-
-    @staticmethod
-    def _numpy_params(match,
-                      _name_parts=partial(re.compile(', ').sub, '`**, **`')):
-        """ Converts NumpyDoc parameter (etc.) sections into Markdown. """
-        name, type, desc = match.group("name", "type", "desc")
-        type = type or match.groupdict().get('just_type', None)
-        desc = desc.strip()
-        name = name and _name_parts(name)
-        return _ToMarkdown._deflist(name, type, desc)
-
-    @staticmethod
-    def _numpy_seealso(match):
-        """
-        Converts NumpyDoc "See Also" section either into referenced code,
-        optionally within a definition list.
-        """
-        spec_with_desc, simple_list = match.groups()
-        if spec_with_desc:
-            return '\n\n'.join('`{}`\n:   {}'.format(*map(str.strip, line.split(':', 1)))
-                               for line in filter(None, spec_with_desc.split('\n')))
-        return ', '.join('`{}`'.format(i) for i in simple_list.split(', '))
-
-    @staticmethod
-    def _numpy_sections(match):
-        """
-        Convert sections with parameter, return, and see also lists to Markdown
-        lists.
-        """
-        section, body = match.groups()
-        if section.title() == 'See Also':
-            body = re.sub(r'^((?:\n?[\w.]* ?: .*)+)|(.*\w.*)',
-                          _ToMarkdown._numpy_seealso, body)
-        elif section.title() in ('Returns', 'Yields', 'Raises', 'Warns'):
-            body = re.sub(r'^(?:(?P\*{0,2}\w+(?:, \*{0,2}\w+)*)'
-                          r'(?: ?: (?P.*))|'
-                          r'(?P\w[^\n`*]*))(?(?:\n(?: {4}.*|$))*)',
-                          _ToMarkdown._numpy_params, body, flags=re.MULTILINE)
-        else:
-            body = re.sub(r'^(?P\*{0,2}\w+(?:, \*{0,2}\w+)*)'
-                          r'(?: ?: (?P.*))?(?(?:\n(?: {4}.*|$))*)',
-                          _ToMarkdown._numpy_params, body, flags=re.MULTILINE)
-        return section + '\n-----\n' + body
-
-    @staticmethod
-    def numpy(text):
-        """
-        Convert `text` in numpydoc docstring format to Markdown
-        to be further converted later.
-        """
-        return re.sub(r'^(\w[\w ]+)\n-{3,}\n'
-                      r'((?:(?!.+\n-+).*$\n?)*)',
-                      _ToMarkdown._numpy_sections, text, flags=re.MULTILINE)
-
-    @staticmethod
-    def _is_indented_4_spaces(txt, _3_spaces_or_less=re.compile(r'\n\s{0,3}\S').search):
-        return '\n' not in txt or not _3_spaces_or_less(txt)
-
-    @staticmethod
-    def _fix_indent(name, type, desc):
-        """Maybe fix indent from 2 to 4 spaces."""
-        if not _ToMarkdown._is_indented_4_spaces(desc):
-            desc = desc.replace('\n', '\n  ')
-        return name, type, desc
-
-    @staticmethod
-    def indent(indent, text, *, clean_first=False):
-        if clean_first:
-            text = inspect.cleandoc(text)
-        return re.sub(r'\n', '\n' + indent, indent + text.rstrip())
-
-    @staticmethod
-    def google(text,
-               _googledoc_sections=partial(
-                   re.compile(r'^([A-Z]\w+):$\n((?:\n?(?: {2,}.*|$))+)', re.MULTILINE).sub,
-                   lambda m, _params=partial(
-                           re.compile(r'^([\w*]+)(?: \(([\w.,=\[\] ]+)\))?: '
-                                      r'((?:.*)(?:\n(?: {2,}.*|$))*)', re.MULTILINE).sub,
-                           lambda m: _ToMarkdown._deflist(*_ToMarkdown._fix_indent(*m.groups()))): (
-                       m.group() if not m.group(2) else '\n{}\n-----\n{}'.format(
-                           m.group(1), _params(inspect.cleandoc('\n' + m.group(2))))))):
-        """
-        Convert `text` in Google-style docstring format to Markdown
-        to be further converted later.
-        """
-        return _googledoc_sections(text)
-
-    @staticmethod
-    def _admonition(match, module=None, limit_types=None):
-        indent, type, value, text = match.groups()
-
-        if limit_types and type not in limit_types:
-            return match.group(0)
-
-        if type == 'include' and module:
-            try:
-                return _ToMarkdown._include_file(indent, value,
-                                                 _ToMarkdown._directive_opts(text), module)
-            except Exception as e:
-                raise RuntimeError('`.. include:: {}` error in module {!r}: {}'
-                                   .format(value, module.name, e))
-        if type in ('image', 'figure'):
-            return '{}![{}]({})\n'.format(
-                indent, text.translate(str.maketrans({'\n': ' ',
-                                                      '[': '\\[',
-                                                      ']': '\\]'})).strip(), value)
-        if type == 'math':
-            return _ToMarkdown.indent(indent,
-                                      '\\[ ' + text.strip() + ' \\]',
-                                      clean_first=True)
-
-        if type == 'versionchanged':
-            title = 'Changed in version: ' + value
-        elif type == 'versionadded':
-            title = 'Added in version: ' + value
-        elif type == 'deprecated' and value:
-            title = 'Deprecated since version: ' + value
-        elif type == 'admonition':
-            title = value
-        elif type.lower() == 'todo':
-            title = 'TODO'
-            text = value + ' ' + text
-        else:
-            title = type.capitalize()
-            if value:
-                title += ': ' + value
-
-        text = _ToMarkdown.indent(indent + '    ', text, clean_first=True)
-        return '{}!!! {} "{}"\n{}\n'.format(indent, type, title, text)
-
-    @staticmethod
-    def admonitions(text, module, limit_types=None):
-        """
-        Process reStructuredText's block directives such as
-        `.. warning::`, `.. deprecated::`, `.. versionadded::`, etc.
-        and turn them into Python-M>arkdown admonitions.
-
-        `limit_types` is optionally a set of directives to limit processing to.
-
-        See: https://python-markdown.github.io/extensions/admonition/
-        """
-        substitute = partial(re.compile(r'^(?P *)\.\. ?(\w+)::(?: *(.*))?'
-                                        r'((?:\n(?:(?P=indent) +.*| *$))*)', re.MULTILINE).sub,
-                             partial(_ToMarkdown._admonition, module=module,
-                                     limit_types=limit_types))
-        # Apply twice for nested (e.g. image inside warning)
-        return substitute(substitute(text))
-
-    @staticmethod
-    def _include_file(indent: str, path: str, options: dict, module: pdoc.Module) -> str:
-        start_line = int(options.get('start-line', 0))
-        end_line = int(options.get('end-line', 0)) or None
-        start_after = options.get('start-after')
-        end_before = options.get('end-before')
-
-        with open(os.path.join(os.path.dirname(module.obj.__file__), path),
-                  encoding='utf-8') as f:
-            text = ''.join(list(f)[start_line:end_line])
-
-        if start_after:
-            text = text[text.index(start_after) + len(start_after):]
-        if end_before:
-            text = text[:text.index(end_before)]
-
-        return _ToMarkdown.indent(indent, text)
-
-    @staticmethod
-    def _directive_opts(text: str) -> dict:
-        return dict(re.findall(r'^ *:([^:]+): *(.*)', text, re.MULTILINE))
-
-    @staticmethod
-    def doctests(text,
-                 _indent_doctests=partial(
-                     re.compile(r'(?:^(?P```|~~~).*\n)?'
-                                r'(?:^>>>.*'
-                                r'(?:\n(?:(?:>>>|\.\.\.).*))*'
-                                r'(?:\n.*)?\n\n?)+'
-                                r'(?P=fence)?', re.MULTILINE).sub,
-                     lambda m: (m.group(0) if m.group('fence') else
-                                ('\n    ' + '\n    '.join(m.group(0).split('\n')) + '\n\n')))):
-        """
-        Indent non-fenced (`~~~`) top-level (0-indented)
-        doctest blocks so they render as code.
-        """
-        if not text.endswith('\n'):  # Needed for the r'(?:\n.*)?\n\n?)+' line (GH-72)
-            text += '\n'
-        return _indent_doctests(text)
-
-    @staticmethod
-    def raw_urls(text):
-        """Wrap URLs in Python-Markdown-compatible ."""
-        return re.sub(r'(?)\s]+)(\s*)', r'\1<\2>\3', text)
-
-
-class _MathPattern(InlineProcessor):
-    NAME = 'pdoc-math'
-    PATTERN = r'(?'):  # CUT was put into its own paragraph
-        toc = toc[:-3].rstrip()
-    return toc
-
-
-def format_git_link(template: str, dobj: pdoc.Doc):
-    """
-    Interpolate `template` as a formatted string literal using values extracted
-    from `dobj` and the working environment.
-    """
-    if not template:
-        return None
-    try:
-        if 'commit' in _str_template_fields(template):
-            commit = _git_head_commit()
-        abs_path = inspect.getfile(inspect.unwrap(dobj.obj))
-        path = _project_relative_path(abs_path)
-        lines, start_line = inspect.getsourcelines(dobj.obj)
-        end_line = start_line + len(lines) - 1
-        url = template.format(**locals())
-        return url
-    except Exception:
-        warn('format_git_link for {} failed:\n{}'.format(dobj.obj, traceback.format_exc()))
-        return None
-
-
-@lru_cache()
-def _git_head_commit():
-    """
-    If the working directory is part of a git repository, return the
-    head git commit hash. Otherwise, raise a CalledProcessError.
-    """
-    process_args = ['git', 'rev-parse', 'HEAD']
-    try:
-        commit = subprocess.check_output(process_args, universal_newlines=True).strip()
-        return commit
-    except OSError as error:
-        warn("git executable not found on system:\n{}".format(error))
-    except subprocess.CalledProcessError as error:
-        warn(
-            "Ensure pdoc is run within a git repository.\n"
-            "`{}` failed with output:\n{}"
-            .format(' '.join(process_args), error.output)
-        )
-    return None
-
-
-@lru_cache()
-def _git_project_root():
-    """
-    Return the path to project root directory or None if indeterminate.
-    """
-    path = None
-    for cmd in (['git', 'rev-parse', '--show-superproject-working-tree'],
-                ['git', 'rev-parse', '--show-toplevel']):
-        try:
-            path = subprocess.check_output(cmd, universal_newlines=True).rstrip('\r\n')
-            if path:
-                break
-        except (subprocess.CalledProcessError, OSError):
-            pass
-    return path
-
-
-@lru_cache()
-def _project_relative_path(absolute_path):
-    """
-    Convert an absolute path of a python source file to a project-relative path.
-    Assumes the project's path is either the current working directory or
-    Python library installation.
-    """
-    from distutils.sysconfig import get_python_lib
-    for prefix_path in (_git_project_root() or os.getcwd(),
-                        get_python_lib()):
-        common_path = os.path.commonpath([prefix_path, absolute_path])
-        if common_path == prefix_path:
-            # absolute_path is a descendant of prefix_path
-            return os.path.relpath(absolute_path, prefix_path)
-    raise RuntimeError(
-        "absolute path {!r} is not a descendant of the current working directory "
-        "or of the system's python library."
-        .format(absolute_path)
-    )
-
-
-@lru_cache()
-def _str_template_fields(template):
-    """
-    Return a list of `str.format` field names in a template string.
-    """
-    from string import Formatter
-    return [
-        field_name
-        for _, field_name, _, _ in Formatter().parse(template)
-        if field_name is not None
-    ]
diff --git a/pdoc_templates/pdf.mako b/pdoc_templates/pdf.mako
deleted file mode 100644
index 50e7989..0000000
--- a/pdoc_templates/pdf.mako
+++ /dev/null
@@ -1,185 +0,0 @@
-<%!
-    import re
-    import pdoc
-    from pdoc.html_helpers import to_markdown, format_git_link
-
-    def link(d, fmt='{}'):
-        name = fmt.format(d.qualname + ('()' if isinstance(d, pdoc.Function) else ''))
-        if isinstance(d, pdoc.External):
-            return name
-        return '[{}](#{})'.format(name, d.refname)
-
-    def _to_md(text, module):
-        text = to_markdown(text, module=module, link=link)
-        # Setext H2 headings to atx H2 headings
-        text = re.sub(r'\n(.+)\n-{3,}\n', r'\n## \1\n\n', text)
-        # Convert admonitions into simpler paragraphs, dedent contents
-        text = re.sub(r'^(?P( *))!!! \w+ \"([^\"]*)\"(.*(?:\n(?P=indent) +.*)*)',
-                      lambda m: '{}**{}:** {}'.format(m.group(2), m.group(3),
-                                                      re.sub('\n {,4}', '\n', m.group(4))),
-                      text, flags=re.MULTILINE)
-        return text
-
-    def subh(text, level=2):
-        # Deepen heading levels so H2 becomes H4 etc.
-        return re.sub(r'\n(#+) +(.+)\n', r'\n%s\1 \2\n' % ('#' * level), text)
-%>
-
-<%def name="title(level, string, id=None)">
-    <% id = ' {#%s}' % id if id is not None else '' %>
-${('#' * level) + ' ' + string + id}
-
-
-<%def name="funcdef(f)">
-    <%
-        returns = show_type_annotations and f.return_annotation() or ''
-        if returns:
-            returns = ' -> ' + returns
-    %>
-> `${f.funcdef()} ${f.name}(${', '.join(f.params(annotate=show_type_annotations))})${returns}`
-
-
-<%def name="classdef(c)">
-> `class ${c.name}(${', '.join(c.params(annotate=show_type_annotations))})`
-
-
-<%def name="show_source(d)">
-  % if (show_source_code or git_link_template) and d.source and d.obj is not getattr(d.inherits, 'obj', None):
-    <% git_link = format_git_link(git_link_template, d) %>
-[[view code]](${git_link})
-  %endif
-
-
----
-description: |
-    API documentation for modules: ${', '.join(m.name for m in modules)}.
-
-lang: en
-
-classoption: oneside
-geometry: margin=1in
-papersize: a4
-
-linkcolor: blue
-links-as-notes: true
-...
-% for module in modules:
-<%
-    submodules = module.submodules()
-    variables = module.variables()
-    functions = module.functions()
-    classes = module.classes()
-
-    def to_md(text):
-        return _to_md(text, module)
-%>
-
--------------------------------------------
-
-${title(1, ('Namespace' if module.is_namespace else 'Module') + ' `%s`' % module.name, module.refname)}
-${module.docstring | to_md}
-
-% if submodules:
-${title(2, 'Sub-modules')}
-    % for m in submodules:
-* [${m.name}](#${m.refname})
-    % endfor
-% endif
-
-% if variables:
-${title(2, 'Variables')}
-    % for v in variables:
-${title(3, 'Variable `%s`' % v.name, v.refname)}
-${show_source(v)}
-${v.docstring | to_md, subh, subh}
-    % endfor
-% endif
-
-% if functions:
-${title(2, 'Functions')}
-    % for f in functions:
-${title(3, 'Function `%s`' % f.name, f.refname)}
-${show_source(f)}
-
-${funcdef(f)}
-
-${f.docstring | to_md, subh, subh}
-    % endfor
-% endif
-
-% if classes:
-${title(2, 'Classes')}
-    % for cls in classes:
-${title(3, 'Class `%s`' % cls.name, cls.refname)}
-${show_source(cls)}
-
-${classdef(cls)}
-
-${cls.docstring | to_md, subh}
-<%
-    class_vars = cls.class_variables(show_inherited_members, sort=sort_identifiers)
-    static_methods = cls.functions(show_inherited_members, sort=sort_identifiers)
-    inst_vars = cls.instance_variables(show_inherited_members, sort=sort_identifiers)
-    methods = cls.methods(show_inherited_members, sort=sort_identifiers)
-    mro = cls.mro()
-    subclasses = cls.subclasses()
-%>
-        % if mro:
-${title(4, 'Ancestors (in MRO)')}
-            % for c in mro:
-* [${c.refname}](#${c.refname})
-            % endfor
-        % endif
-
-        % if subclasses:
-${title(4, 'Descendants')}
-            % for c in subclasses:
-* [${c.refname}](#${c.refname})
-            % endfor
-        % endif
-
-        % if class_vars:
-${title(4, 'Class variables')}
-            % for v in class_vars:
-${title(5, 'Variable `%s`' % v.name, v.refname)}
-${v.docstring | to_md, subh, subh}
-            % endfor
-        % endif
-
-        % if inst_vars:
-${title(4, 'Instance variables')}
-            % for v in inst_vars:
-${title(5, 'Variable `%s`' % v.name, v.refname)}
-${v.docstring | to_md, subh, subh}
-            % endfor
-        % endif
-
-        % if static_methods:
-${title(4, 'Static methods')}
-            % for f in static_methods:
-${title(5, '`Method %s`' % f.name, f.refname)}
-
-${funcdef(f)}
-
-${f.docstring | to_md, subh, subh}
-            % endfor
-        % endif
-
-        % if methods:
-${title(4, 'Methods')}
-            % for f in methods:
-${title(5, 'Method `%s`' % f.name, f.refname)}
-
-${funcdef(f)}
-
-${f.docstring | to_md, subh, subh}
-            % endfor
-        % endif
-    % endfor
-% endif
-
-##\## for module in modules:
-% endfor
-
------
-Generated by *pdoc* ${pdoc.__version__} ().
diff --git a/pdoc_templates/pdoc.css b/pdoc_templates/pdoc.css
deleted file mode 100644
index a563b44..0000000
--- a/pdoc_templates/pdoc.css
+++ /dev/null
@@ -1,381 +0,0 @@
-  .flex {
-    display: flex !important;
-  }
-
-  body {
-    line-height: 1.5em;
-    background: black;
-    color: #DDD;
-    max-width: 140ch;
-  }
-
-  #content {
-    padding: 20px;
-  }
-
-  #sidebar {
-    padding: 30px;
-    overflow: hidden;
-  }
-
-  .http-server-breadcrumbs {
-    font-size: 130%;
-    margin: 0 0 15px 0;
-  }
-
-  #footer {
-    font-size: .75em;
-    padding: 5px 30px;
-    border-top: 1px solid #ddd;
-    text-align: right;
-  }
-    #footer p {
-      margin: 0 0 0 1em;
-      display: inline-block;
-    }
-    #footer p:last-child {
-      margin-right: 30px;
-    }
-
-  h1, h2, h3, h4, h5 {
-    font-weight: 300;
-  }
-  h1 {
-    font-size: 2.5em;
-    line-height: 1.1em;
-    border-top: 20px white;
-  }
-  h2 {
-    font-size: 1.75em;
-    margin: 1em 0 .50em 0;
-  }
-  h3 {
-    font-size: 1.4em;
-    margin: 25px 0 10px 0;
-  }
-  h4 {
-    margin: 0;
-    font-size: 105%;
-  }
-
-  a {
-    color: #999;
-    text-decoration: none;
-    transition: color .3s ease-in-out;
-  }
-  a:hover {
-    color: #18d;
-  }
-
-  .title code {
-    font-weight: bold;
-  }
-  h2[id^="header-"] {
-    margin-top: 2em;
-  }
-  .ident {
-    color: #7ff;
-  }
-
-  pre code {
-    background: transparent;
-    font-size: .8em;
-    line-height: 1.4em;
-  }
-  code {
-    background: #0d0d0e;
-    padding: 1px 4px;
-    overflow-wrap: break-word;
-  }
-  h1 code { background: transparent }
-
-  pre {
-    background: #111;
-    border: 0;
-    border-top: 1px solid #ccc;
-    border-bottom: 1px solid #ccc;
-    margin: 1em 0;
-    padding: 1ex;
-  }
-
-  #http-server-module-list {
-    display: flex;
-    flex-flow: column;
-  }
-    #http-server-module-list div {
-      display: flex;
-    }
-    #http-server-module-list dt {
-      min-width: 10%;
-    }
-    #http-server-module-list p {
-      margin-top: 0;
-    }
-
-  .toc ul,
-  #index {
-    list-style-type: none;
-    margin: 0;
-    padding: 0;
-  }
-    #index code {
-      background: transparent;
-    }
-    #index h3 {
-      border-bottom: 1px solid #ddd;
-    }
-    #index ul {
-      padding: 0;
-    }
-    #index h4 {
-      font-weight: bold;
-    }
-    #index h4 + ul {
-      margin-bottom:.6em;
-    }
-    /* Make TOC lists have 2+ columns when viewport is wide enough.
-       Assuming ~20-character identifiers and ~30% wide sidebar. */
-    @media (min-width: 200ex) { #index .two-column { column-count: 2 } }
-    @media (min-width: 300ex) { #index .two-column { column-count: 3 } }
-
-  dl {
-    margin-bottom: 2em;
-  }
-    dl dl:last-child {
-      margin-bottom: 4em;
-    }
-  dd {
-    margin: 0 0 1em 3em;
-  }
-    #header-classes + dl > dd {
-      margin-bottom: 3em;
-    }
-    dd dd {
-      margin-left: 2em;
-    }
-    dd p {
-      margin: 10px 0;
-    }
-    blockquote code {
-      background: #111;
-      font-weight: bold;
-      font-size: .85em;
-      padding: 5px 10px;
-      display: inline-block;
-      min-width: 40%;
-    }
-      blockquote code:hover {
-        background: #101010;
-      }
-      .name > span:first-child {
-        white-space: nowrap;
-      }
-      .name.class > span:nth-child(2) {
-        margin-left: .4em;
-      }
-    .inherited {
-      color: #777;
-      border-left: 5px solid #eee;
-      padding-left: 1em;
-    }
-    .inheritance em {
-      font-style: normal;
-      font-weight: bold;
-    }
-
-    /* Docstrings titles, e.g. in numpydoc format */
-    .desc h2 {
-      font-weight: 400;
-      font-size: 1.25em;
-    }
-    .desc h3 {
-      font-size: 1em;
-    }
-    .desc dt code {
-      background: inherit;  /* Don't grey-back parameters */
-    }
-
-    .source summary,
-    .git-link-div {
-      color: #aaa;
-      text-align: right;
-      font-weight: 400;
-      font-size: .8em;
-      text-transform: uppercase;
-    }
-      .source summary > * {
-        white-space: nowrap;
-        cursor: pointer;
-      }
-      .git-link {
-        color: inherit;
-        margin-left: 1em;
-      }
-    .source pre {
-      max-height: 500px;
-      overflow: auto;
-      margin: 0;
-    }
-    .source pre code {
-      font-size: 12px;
-      overflow: visible;
-    }
-  .hlist {
-    list-style: none;
-  }
-    .hlist li {
-      display: inline;
-    }
-    .hlist li:after {
-      content: ',\2002';
-    }
-    .hlist li:last-child:after {
-      content: none;
-    }
-    .hlist .hlist {
-      display: inline;
-      padding-left: 1em;
-    }
-
-  img {
-    max-width: 100%;
-  }
-
-  .admonition {
-    padding: .1em .5em;
-    margin-bottom: 1em;
-  }
-    .admonition-title {
-      font-weight: bold;
-    }
-    .admonition.note,
-    .admonition.info,
-    .admonition.important {
-      background: #610;
-    }
-    .admonition.todo,
-    .admonition.versionadded,
-    .admonition.tip,
-    .admonition.hint {
-      background: #202;
-    }
-    .admonition.warning,
-    .admonition.versionchanged,
-    .admonition.deprecated {
-      background: #02b;
-    }
-    .admonition.error,
-    .admonition.danger,
-    .admonition.caution {
-      background: darkpink;
-    }
-
-  @media screen and (min-width: 700px) {
-    #sidebar {
-      width: 30%;
-    }
-    #content {
-      width: 70%;
-      max-width: 100ch;
-      padding: 3em 4em;
-      border-left: 1px solid #ddd;
-    }
-    pre code {
-      font-size: 1em;
-    }
-    .item .name {
-      font-size: 1em;
-    }
-    main {
-      display: flex;
-      flex-direction: row-reverse;
-      justify-content: flex-end;
-    }
-    .toc ul ul,
-    #index ul {
-      padding-left: 1.5em;
-    }
-    .toc > ul > li {
-      margin-top: .5em;
-    }
-  }
-
-@media print {
-  #sidebar h1 {
-    page-break-before: always;
-  }
-  .source {
-    display: none;
-  }
-}
-@media print {
-    * {
-        background: transparent !important;
-        color: #000 !important; /* Black prints faster: h5bp.com/s */
-        box-shadow: none !important;
-        text-shadow: none !important;
-    }
-
-    a[href]:after {
-        content: " (" attr(href) ")";
-        font-size: 90%;
-    }
-    /* Internal, documentation links, recognized by having a title,
-       don't need the URL explicity stated. */
-    a[href][title]:after {
-        content: none;
-    }
-
-    abbr[title]:after {
-        content: " (" attr(title) ")";
-    }
-
-    /*
-     * Don't show links for images, or javascript/internal links
-     */
-
-    .ir a:after,
-    a[href^="javascript:"]:after,
-    a[href^="#"]:after {
-        content: "";
-    }
-
-    pre,
-    blockquote {
-        border: 1px solid #999;
-        page-break-inside: avoid;
-    }
-
-    thead {
-        display: table-header-group; /* h5bp.com/t */
-    }
-
-    tr,
-    img {
-        page-break-inside: avoid;
-    }
-
-    img {
-        max-width: 100% !important;
-    }
-
-    @page {
-        margin: 0.5cm;
-    }
-
-    p,
-    h2,
-    h3 {
-        orphans: 3;
-        widows: 3;
-    }
-
-    h1,
-    h2,
-    h3,
-    h4,
-    h5,
-    h6 {
-        page-break-after: avoid;
-    }
-}
diff --git a/pyproject.toml b/pyproject.toml
index 8b875f3..7f1d6b4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -39,15 +39,98 @@ include = [
     ]
 dynamic = ["version"]
 dependencies = [
-    "numpy~=1.21",
-    "scipy",
-    ]
+    "gridlock>=2.1",
+    "numpy>=2.0",
+    "scipy~=1.14",
+]
 
 
 [tool.hatch.version]
 path = "meanas/__init__.py"
 
 [project.optional-dependencies]
-dev = ["pytest", "pdoc", "gridlock"]
-examples = ["gridlock"]
-test = ["pytest"]
+dev = [
+    "meanas[test]",
+    "meanas[docs]",
+    "meanas[examples]",
+    "htmlark>=1.0",
+    "ruff>=0.6",
+    ]
+docs = [
+    "mkdocs>=1.6",
+    "mkdocs-material>=9.5",
+    "mkdocstrings[python]>=0.25",
+    "mkdocs-print-site-plugin>=2.3",
+    "pymdown-extensions>=10.7",
+    "htmlark>=1.0",
+    "ruff>=0.6",
+    ]
+examples = [
+    "matplotlib>=3.10.8",
+    "scikit-rf>=1.0",
+]
+test = ["pytest", "coverage"]
+
+
+[tool.ruff]
+exclude = [
+    ".git",
+    "dist",
+    ]
+line-length = 245
+indent-width = 4
+lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+lint.select = [
+    "NPY", "E", "F", "W", "B", "ANN", "UP", "SLOT", "SIM", "LOG",
+    "C4", "ISC", "PIE", "PT", "RET", "TCH", "PTH", "INT",
+    "ARG", "PL", "R", "TRY",
+    "G010", "G101", "G201", "G202",
+    "Q002", "Q003", "Q004",
+    ]
+lint.ignore = [
+    #"ANN001",   # No annotation
+    "ANN002",   # *args
+    "ANN003",   # **kwargs
+    "ANN401",   # Any
+    "SIM108",   # single-line if / else assignment
+    "RET504",   # x=y+z; return x
+    "PIE790",   # unnecessary pass
+    "ISC003",   # non-implicit string concatenation
+    "C408",     # dict(x=y) instead of {'x': y}
+    "PLR09",    # Too many xxx
+    "PLR2004",  # magic number
+    "PLC0414",  # import x as x
+    "TRY003",   # Long exception message
+    "TRY002",   # Exception()
+    ]
+
+[tool.ruff.lint.per-file-ignores]
+"meanas/test/**/*.py" = ["ANN", "ARG", "TC006"]
+
+
+[[tool.mypy.overrides]]
+module = [
+    "scipy",
+    "scipy.optimize",
+    "scipy.linalg",
+    "scipy.sparse",
+    "scipy.sparse.linalg",
+    ]
+ignore_missing_imports = true
+
+#[tool.uv.sources]
+#gridlock = { path = "../gridlock", editable = true }
+
+[tool.pytest.ini_options]
+addopts = "-rsXx"
+testpaths = ["meanas"]
+markers = [
+    "complete: slower integration and smoke tests intended for full pre-commit confidence runs",
+]
+
+[tool.coverage.run]
+source = ["meanas"]
+
+[tool.coverage.report]
+show_missing = true
+omit = ["meanas/test/*"]
diff --git a/scripts/configure_docs_url.sh b/scripts/configure_docs_url.sh
new file mode 100755
index 0000000..ceacc18
--- /dev/null
+++ b/scripts/configure_docs_url.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -Eeuo pipefail
+
+ROOT="$(git rev-parse --show-toplevel)"
+cd "$ROOT"
+
+if [[ $# -gt 1 ]]; then
+    echo "usage: $0 [docs-site-url]" >&2
+    exit 2
+fi
+
+if [[ $# -eq 1 ]]; then
+    git config meanas.docsSiteUrl "$1"
+    echo "Configured meanas.docsSiteUrl=$1"
+    exit 0
+fi
+
+CURRENT_URL="$(git config --get meanas.docsSiteUrl || true)"
+if [[ -n "$CURRENT_URL" ]]; then
+    echo "$CURRENT_URL"
+else
+    echo "meanas.docsSiteUrl is not configured" >&2
+    exit 1
+fi
diff --git a/scripts/prepare_docs_sources.py b/scripts/prepare_docs_sources.py
new file mode 100644
index 0000000..7e9bcc5
--- /dev/null
+++ b/scripts/prepare_docs_sources.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+"""Prepare a temporary source tree for docs generation.
+
+The live source keeps readable display-math blocks written as standalone
+`$$ ... $$` docstring sections. MkDocs + mkdocstrings does not consistently
+preserve those blocks as MathJax input when they appear inside API docstrings,
+so the docs build rewrites them in a temporary copy into explicit
+`
...
` containers. +""" + +from __future__ import annotations + +from pathlib import Path +import shutil +import sys + + +def _rewrite_display_math(text: str) -> str: + lines = text.splitlines(keepends=True) + output: list[str] = [] + in_block = False + block_indent = "" + + for line in lines: + stripped = line.strip() + indent = line[: len(line) - len(line.lstrip())] + + if not in_block: + if stripped == "$$": + block_indent = indent + output.append(f'{block_indent}
\\[\n') + in_block = True + continue + + if stripped.startswith("$$") and stripped.endswith("$$") and stripped != "$$": + body = stripped[2:-2].strip() + output.append(f'{indent}
\\[ {body} \\]
\n') + continue + + if stripped.startswith("$$"): + block_indent = indent + body = stripped[2:].strip() + output.append(f'{block_indent}
\\[\n') + if body: + output.append(f"{block_indent}{body}\n") + in_block = True + continue + + output.append(line) + continue + + if stripped == "$$": + output.append(f"{block_indent}\\]
\n") + in_block = False + block_indent = "" + continue + + if stripped.endswith("$$"): + body = stripped[:-2].rstrip() + if body: + output.append(f"{block_indent}{body}\n") + output.append(f"{block_indent}\\]
\n") + in_block = False + block_indent = "" + continue + + output.append(line) + + if in_block: + raise ValueError("unterminated display-math block") + + return "".join(output) + + +def main() -> int: + if len(sys.argv) != 3: + print("usage: prepare_docs_sources.py ", file=sys.stderr) + return 2 + + src_dir = Path(sys.argv[1]).resolve() + dst_root = Path(sys.argv[2]).resolve() + dst_pkg = dst_root / src_dir.name + + shutil.copytree(src_dir, dst_pkg) + + for path in dst_pkg.rglob("*.py"): + path.write_text(_rewrite_display_math(path.read_text())) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/publish_docs_branch.sh b/scripts/publish_docs_branch.sh new file mode 100755 index 0000000..0fe1c4e --- /dev/null +++ b/scripts/publish_docs_branch.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +set -Eeuo pipefail + +if [[ $# -ne 2 ]]; then + echo "usage: $0 " >&2 + exit 2 +fi + +SITE_DIR="$1" +BRANCH="$2" + +if [[ ! -d "$SITE_DIR" ]]; then + echo "site directory not found: $SITE_DIR" >&2 + exit 1 +fi + +if ! git rev-parse --git-dir >/dev/null 2>&1; then + echo "must be run inside a git repository" >&2 + exit 1 +fi + +TMP_DIR="$(mktemp -d)" +cleanup() { + git worktree remove --force "$TMP_DIR" >/dev/null 2>&1 || true +} +trap cleanup EXIT + +git fetch origin "$BRANCH" || true + +if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then + git worktree add --detach "$TMP_DIR" "origin/$BRANCH" +else + git worktree add --detach "$TMP_DIR" + git -C "$TMP_DIR" checkout --orphan "$BRANCH" +fi + +find "$TMP_DIR" -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + +cp -R "$SITE_DIR"/. "$TMP_DIR"/ +touch "$TMP_DIR/.nojekyll" + +git -C "$TMP_DIR" config user.name "${GIT_AUTHOR_NAME:-Forgejo Actions}" +git -C "$TMP_DIR" config user.email "${GIT_AUTHOR_EMAIL:-forgejo-actions@localhost}" +git -C "$TMP_DIR" add -A + +if git -C "$TMP_DIR" diff --cached --quiet; then + echo "no docs changes to publish" + exit 0 +fi + +git -C "$TMP_DIR" commit -m "Publish docs for ${GITHUB_SHA:-local build}" +git -C "$TMP_DIR" push --force origin "HEAD:${BRANCH}" diff --git a/scripts/push_with_docs.sh b/scripts/push_with_docs.sh new file mode 100755 index 0000000..1b6e259 --- /dev/null +++ b/scripts/push_with_docs.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +set -Eeuo pipefail + +ROOT="$(git rev-parse --show-toplevel)" +cd "$ROOT" + +CURRENT_BRANCH="$(git branch --show-current)" + +resolve_remote_name() { + local branch="$1" + shift || true + + for arg in "$@"; do + case "$arg" in + --) + break + ;; + -*) + continue + ;; + *) + if git remote get-url "$arg" >/dev/null 2>&1; then + echo "$arg" + return 0 + fi + ;; + esac + done + + git config --get "branch.${branch}.pushRemote" \ + || git config --get remote.pushDefault \ + || git config --get "branch.${branch}.remote" \ + || echo origin +} + +REMOTE_NAME="$(resolve_remote_name "$CURRENT_BRANCH" "$@")" + +git push "$@" + +if [[ "$CURRENT_BRANCH" != "master" ]]; then + echo "[meanas docs push] current branch is '${CURRENT_BRANCH:-}' not 'master'; skipping docs publish" >&2 + exit 0 +fi + +if [[ "$REMOTE_NAME" != "origin" ]]; then + echo "[meanas docs push] push remote is '${REMOTE_NAME}' not 'origin'; skipping docs publish" >&2 + exit 0 +fi + +if ! command -v mkdocs >/dev/null 2>&1; then + echo "[meanas docs push] mkdocs not found; skipping docs publish" >&2 + exit 0 +fi + +DOCS_SITE_URL="${DOCS_SITE_URL:-$(git config --get meanas.docsSiteUrl || true)}" +export DOCS_SITE_URL + +if [[ -n "$DOCS_SITE_URL" ]]; then + echo "[meanas docs push] publishing docs for ${DOCS_SITE_URL}" >&2 +else + echo "[meanas docs push] DOCS_SITE_URL is unset; building docs with relative site_url" >&2 +fi + +echo "[meanas docs push] building docs" >&2 +./make_docs.sh +echo "[meanas docs push] publishing docs-site branch" >&2 +./scripts/publish_docs_branch.sh site docs-site diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..08bad0c --- /dev/null +++ b/uv.lock @@ -0,0 +1,1534 @@ +version = 1 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version < '3.14' and sys_platform == 'emscripten'", + "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845 }, +] + +[[package]] +name = "backrefs" +version = "6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/a6/e325ec73b638d3ede4421b5445d4a0b8b219481826cc079d510100af356c/backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49", size = 7012303 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/39/3765df263e08a4df37f4f43cb5aa3c6c17a4bdd42ecfe841e04c26037171/backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8", size = 381075 }, + { url = "https://files.pythonhosted.org/packages/0f/f0/35240571e1b67ffb19dafb29ab34150b6f59f93f717b041082cdb1bfceb1/backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be", size = 392874 }, + { url = "https://files.pythonhosted.org/packages/e3/63/77e8c9745b4d227cce9f5e0a6f68041278c5f9b18588b35905f5f19c1beb/backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90", size = 398787 }, + { url = "https://files.pythonhosted.org/packages/c5/71/c754b1737ad99102e03fa3235acb6cb6d3ac9d6f596cbc3e5f236705abd8/backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b", size = 400747 }, + { url = "https://files.pythonhosted.org/packages/af/75/be12ba31a6eb20dccef2320cd8ccb3f7d9013b68ba4c70156259fee9e409/backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7", size = 412602 }, + { url = "https://files.pythonhosted.org/packages/21/f8/d02f650c47d05034dcd6f9c8cf94f39598b7a89c00ecda0ecb2911bc27e9/backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7", size = 381077 }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, +] + +[[package]] +name = "certifi" +version = "2026.2.25" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705 }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419 }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901 }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742 }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061 }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239 }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173 }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841 }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304 }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455 }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036 }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739 }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277 }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819 }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281 }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843 }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328 }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061 }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031 }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239 }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589 }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733 }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652 }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229 }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552 }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806 }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316 }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274 }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468 }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460 }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330 }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828 }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627 }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008 }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303 }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282 }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595 }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986 }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711 }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036 }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998 }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056 }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537 }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176 }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723 }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085 }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819 }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915 }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234 }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042 }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706 }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727 }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882 }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860 }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564 }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276 }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238 }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189 }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352 }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024 }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869 }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541 }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634 }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384 }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133 }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257 }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851 }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393 }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251 }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609 }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014 }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979 }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238 }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110 }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824 }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103 }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194 }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827 }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168 }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018 }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958 }, +] + +[[package]] +name = "click" +version = "8.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773 }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149 }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222 }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234 }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555 }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238 }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218 }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867 }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677 }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234 }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123 }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419 }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979 }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653 }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536 }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397 }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601 }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288 }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386 }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018 }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567 }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655 }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257 }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034 }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672 }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234 }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169 }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859 }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062 }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932 }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024 }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578 }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524 }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730 }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897 }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751 }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486 }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106 }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548 }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297 }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023 }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157 }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570 }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713 }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189 }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251 }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810 }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871 }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264 }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819 }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650 }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833 }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692 }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424 }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300 }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769 }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892 }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748 }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554 }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118 }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555 }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295 }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027 }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428 }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331 }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831 }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809 }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593 }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202 }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207 }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315 }, +] + +[[package]] +name = "coverage" +version = "7.13.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/37/d24c8f8220ff07b839b2c043ea4903a33b0f455abe673ae3c03bbdb7f212/coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d", size = 219381 }, + { url = "https://files.pythonhosted.org/packages/35/8b/cd129b0ca4afe886a6ce9d183c44d8301acbd4ef248622e7c49a23145605/coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587", size = 219880 }, + { url = "https://files.pythonhosted.org/packages/55/2f/e0e5b237bffdb5d6c530ce87cc1d413a5b7d7dfd60fb067ad6d254c35c76/coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642", size = 250303 }, + { url = "https://files.pythonhosted.org/packages/92/be/b1afb692be85b947f3401375851484496134c5554e67e822c35f28bf2fbc/coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b", size = 252218 }, + { url = "https://files.pythonhosted.org/packages/da/69/2f47bb6fa1b8d1e3e5d0c4be8ccb4313c63d742476a619418f85740d597b/coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686", size = 254326 }, + { url = "https://files.pythonhosted.org/packages/d5/d0/79db81da58965bd29dabc8f4ad2a2af70611a57cba9d1ec006f072f30a54/coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743", size = 256267 }, + { url = "https://files.pythonhosted.org/packages/e5/32/d0d7cc8168f91ddab44c0ce4806b969df5f5fdfdbb568eaca2dbc2a04936/coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75", size = 250430 }, + { url = "https://files.pythonhosted.org/packages/4d/06/a055311d891ddbe231cd69fdd20ea4be6e3603ffebddf8704b8ca8e10a3c/coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209", size = 252017 }, + { url = "https://files.pythonhosted.org/packages/d6/f6/d0fd2d21e29a657b5f77a2fe7082e1568158340dceb941954f776dce1b7b/coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a", size = 250080 }, + { url = "https://files.pythonhosted.org/packages/4e/ab/0d7fb2efc2e9a5eb7ddcc6e722f834a69b454b7e6e5888c3a8567ecffb31/coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e", size = 253843 }, + { url = "https://files.pythonhosted.org/packages/ba/6f/7467b917bbf5408610178f62a49c0ed4377bb16c1657f689cc61470da8ce/coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd", size = 249802 }, + { url = "https://files.pythonhosted.org/packages/75/2c/1172fb689df92135f5bfbbd69fc83017a76d24ea2e2f3a1154007e2fb9f8/coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8", size = 250707 }, + { url = "https://files.pythonhosted.org/packages/67/21/9ac389377380a07884e3b48ba7a620fcd9dbfaf1d40565facdc6b36ec9ef/coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf", size = 221880 }, + { url = "https://files.pythonhosted.org/packages/af/7f/4cd8a92531253f9d7c1bbecd9fa1b472907fb54446ca768c59b531248dc5/coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9", size = 222816 }, + { url = "https://files.pythonhosted.org/packages/12/a6/1d3f6155fb0010ca68eba7fe48ca6c9da7385058b77a95848710ecf189b1/coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028", size = 221483 }, + { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554 }, + { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908 }, + { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419 }, + { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159 }, + { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270 }, + { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538 }, + { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821 }, + { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191 }, + { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337 }, + { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404 }, + { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903 }, + { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780 }, + { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093 }, + { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900 }, + { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515 }, + { url = "https://files.pythonhosted.org/packages/74/8c/74fedc9663dcf168b0a059d4ea756ecae4da77a489048f94b5f512a8d0b3/coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1", size = 219576 }, + { url = "https://files.pythonhosted.org/packages/0c/c9/44fb661c55062f0818a6ffd2685c67aa30816200d5f2817543717d4b92eb/coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3", size = 219942 }, + { url = "https://files.pythonhosted.org/packages/5f/13/93419671cee82b780bab7ea96b67c8ef448f5f295f36bf5031154ec9a790/coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26", size = 250935 }, + { url = "https://files.pythonhosted.org/packages/ac/68/1666e3a4462f8202d836920114fa7a5ee9275d1fa45366d336c551a162dd/coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3", size = 253541 }, + { url = "https://files.pythonhosted.org/packages/4e/5e/3ee3b835647be646dcf3c65a7c6c18f87c27326a858f72ab22c12730773d/coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b", size = 254780 }, + { url = "https://files.pythonhosted.org/packages/44/b3/cb5bd1a04cfcc49ede6cd8409d80bee17661167686741e041abc7ee1b9a9/coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a", size = 256912 }, + { url = "https://files.pythonhosted.org/packages/1b/66/c1dceb7b9714473800b075f5c8a84f4588f887a90eb8645282031676e242/coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969", size = 251165 }, + { url = "https://files.pythonhosted.org/packages/b7/62/5502b73b97aa2e53ea22a39cf8649ff44827bef76d90bf638777daa27a9d/coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161", size = 252908 }, + { url = "https://files.pythonhosted.org/packages/7d/37/7792c2d69854397ca77a55c4646e5897c467928b0e27f2d235d83b5d08c6/coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15", size = 250873 }, + { url = "https://files.pythonhosted.org/packages/a3/23/bc866fb6163be52a8a9e5d708ba0d3b1283c12158cefca0a8bbb6e247a43/coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1", size = 255030 }, + { url = "https://files.pythonhosted.org/packages/7d/8b/ef67e1c222ef49860701d346b8bbb70881bef283bd5f6cbba68a39a086c7/coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6", size = 250694 }, + { url = "https://files.pythonhosted.org/packages/46/0d/866d1f74f0acddbb906db212e096dee77a8e2158ca5e6bb44729f9d93298/coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17", size = 252469 }, + { url = "https://files.pythonhosted.org/packages/7a/f5/be742fec31118f02ce42b21c6af187ad6a344fed546b56ca60caacc6a9a0/coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85", size = 222112 }, + { url = "https://files.pythonhosted.org/packages/66/40/7732d648ab9d069a46e686043241f01206348e2bbf128daea85be4d6414b/coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b", size = 222923 }, + { url = "https://files.pythonhosted.org/packages/48/af/fea819c12a095781f6ccd504890aaddaf88b8fab263c4940e82c7b770124/coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664", size = 221540 }, + { url = "https://files.pythonhosted.org/packages/23/d2/17879af479df7fbbd44bd528a31692a48f6b25055d16482fdf5cdb633805/coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d", size = 220262 }, + { url = "https://files.pythonhosted.org/packages/5b/4c/d20e554f988c8f91d6a02c5118f9abbbf73a8768a3048cb4962230d5743f/coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0", size = 220617 }, + { url = "https://files.pythonhosted.org/packages/29/9c/f9f5277b95184f764b24e7231e166dfdb5780a46d408a2ac665969416d61/coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806", size = 261912 }, + { url = "https://files.pythonhosted.org/packages/d5/f6/7f1ab39393eeb50cfe4747ae8ef0e4fc564b989225aa1152e13a180d74f8/coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3", size = 263987 }, + { url = "https://files.pythonhosted.org/packages/a0/d7/62c084fb489ed9c6fbdf57e006752e7c516ea46fd690e5ed8b8617c7d52e/coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9", size = 266416 }, + { url = "https://files.pythonhosted.org/packages/a9/f6/df63d8660e1a0bff6125947afda112a0502736f470d62ca68b288ea762d8/coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd", size = 267558 }, + { url = "https://files.pythonhosted.org/packages/5b/02/353ca81d36779bd108f6d384425f7139ac3c58c750dcfaafe5d0bee6436b/coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606", size = 261163 }, + { url = "https://files.pythonhosted.org/packages/2c/16/2e79106d5749bcaf3aee6d309123548e3276517cd7851faa8da213bc61bf/coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e", size = 263981 }, + { url = "https://files.pythonhosted.org/packages/29/c7/c29e0c59ffa6942030ae6f50b88ae49988e7e8da06de7ecdbf49c6d4feae/coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0", size = 261604 }, + { url = "https://files.pythonhosted.org/packages/40/48/097cdc3db342f34006a308ab41c3a7c11c3f0d84750d340f45d88a782e00/coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87", size = 265321 }, + { url = "https://files.pythonhosted.org/packages/bb/1f/4994af354689e14fd03a75f8ec85a9a68d94e0188bbdab3fc1516b55e512/coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479", size = 260502 }, + { url = "https://files.pythonhosted.org/packages/22/c6/9bb9ef55903e628033560885f5c31aa227e46878118b63ab15dc7ba87797/coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2", size = 262688 }, + { url = "https://files.pythonhosted.org/packages/14/4f/f5df9007e50b15e53e01edea486814783a7f019893733d9e4d6caad75557/coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a", size = 222788 }, + { url = "https://files.pythonhosted.org/packages/e1/98/aa7fccaa97d0f3192bec013c4e6fd6d294a6ed44b640e6bb61f479e00ed5/coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819", size = 223851 }, + { url = "https://files.pythonhosted.org/packages/3d/8b/e5c469f7352651e5f013198e9e21f97510b23de957dd06a84071683b4b60/coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911", size = 222104 }, + { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621 }, + { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953 }, + { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992 }, + { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503 }, + { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852 }, + { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161 }, + { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021 }, + { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858 }, + { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823 }, + { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099 }, + { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638 }, + { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295 }, + { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360 }, + { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174 }, + { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739 }, + { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351 }, + { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612 }, + { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985 }, + { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107 }, + { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513 }, + { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650 }, + { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089 }, + { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982 }, + { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579 }, + { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316 }, + { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427 }, + { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745 }, + { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146 }, + { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254 }, + { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276 }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346 }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, +] + +[[package]] +name = "float-raster" +version = "0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/7e/57d91306c966fc5ce8e068650741b599011a14e96ff0b8ec226668094287/float_raster-0.8.tar.gz", hash = "sha256:90e9c00d3908a8e0d50cd97c6df42055ac0fcf900302a504a4becaa024c60c22", size = 29233 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/69/bcdcf1b52420d4b97ab6a18798a4ebb92292948b555a9a6782cb628821e6/float_raster-0.8-py3-none-any.whl", hash = "sha256:7e4ce9ffaf972e3ee788f16b06ee0eb07488b74634ee6f3db2402bf10ef29be7", size = 42469 }, +] + +[[package]] +name = "fonttools" +version = "4.61.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/f9/0e84d593c0e12244150280a630999835a64f2852276161b62a0f98318de0/fonttools-4.61.0.tar.gz", hash = "sha256:ec520a1f0c7758d7a858a00f090c1745f6cde6a7c5e76fb70ea4044a15f712e7", size = 3561884 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/be/5aa89cdddf2863d8afbdc19eb8ec5d8d35d40eeeb8e6cf52c5ff1c2dbd33/fonttools-4.61.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a32a16951cbf113d38f1dd8551b277b6e06e0f6f776fece0f99f746d739e1be3", size = 2847553 }, + { url = "https://files.pythonhosted.org/packages/0d/3e/6ff643b07cead1236a534f51291ae2981721cf419135af5b740c002a66dd/fonttools-4.61.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:328a9c227984bebaf69f3ac9062265f8f6acc7ddf2e4e344c63358579af0aa3d", size = 2388298 }, + { url = "https://files.pythonhosted.org/packages/c3/15/fca8dfbe7b482e6f240b1aad0ed7c6e2e75e7a28efa3d3a03b570617b5e5/fonttools-4.61.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f0bafc8a3b3749c69cc610e5aa3da832d39c2a37a68f03d18ec9a02ecaac04a", size = 5054133 }, + { url = "https://files.pythonhosted.org/packages/6a/a2/821c61c691b21fd09e07528a9a499cc2b075ac83ddb644aa16c9875a64bc/fonttools-4.61.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b5ca59b7417d149cf24e4c1933c9f44b2957424fc03536f132346d5242e0ebe5", size = 5031410 }, + { url = "https://files.pythonhosted.org/packages/e8/f6/8b16339e93d03c732c8a23edefe3061b17a5f9107ddc47a3215ecd054cac/fonttools-4.61.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:df8cbce85cf482eb01f4551edca978c719f099c623277bda8332e5dbe7dba09d", size = 5030005 }, + { url = "https://files.pythonhosted.org/packages/ac/eb/d4e150427bdaa147755239c931bbce829a88149ade5bfd8a327afe565567/fonttools-4.61.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7fb5b84f48a6a733ca3d7f41aa9551908ccabe8669ffe79586560abcc00a9cfd", size = 5154026 }, + { url = "https://files.pythonhosted.org/packages/7f/5f/3dd00ce0dba6759943c707b1830af8c0bcf6f8f1a9fe46cb82e7ac2aaa74/fonttools-4.61.0-cp311-cp311-win32.whl", hash = "sha256:787ef9dfd1ea9fe49573c272412ae5f479d78e671981819538143bec65863865", size = 2276035 }, + { url = "https://files.pythonhosted.org/packages/4e/44/798c472f096ddf12955eddb98f4f7c906e7497695d04ce073ddf7161d134/fonttools-4.61.0-cp311-cp311-win_amd64.whl", hash = "sha256:14fafda386377b6131d9e448af42d0926bad47e038de0e5ba1d58c25d621f028", size = 2327290 }, + { url = "https://files.pythonhosted.org/packages/00/5d/19e5939f773c7cb05480fe2e881d63870b63ee2b4bdb9a77d55b1d36c7b9/fonttools-4.61.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e24a1565c4e57111ec7f4915f8981ecbb61adf66a55f378fdc00e206059fcfef", size = 2846930 }, + { url = "https://files.pythonhosted.org/packages/25/b2/0658faf66f705293bd7e739a4f038302d188d424926be9c59bdad945664b/fonttools-4.61.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e2bfacb5351303cae9f072ccf3fc6ecb437a6f359c0606bae4b1ab6715201d87", size = 2383016 }, + { url = "https://files.pythonhosted.org/packages/29/a3/1fa90b95b690f0d7541f48850adc40e9019374d896c1b8148d15012b2458/fonttools-4.61.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0bdcf2e29d65c26299cc3d502f4612365e8b90a939f46cd92d037b6cb7bb544a", size = 4949425 }, + { url = "https://files.pythonhosted.org/packages/af/00/acf18c00f6c501bd6e05ee930f926186f8a8e268265407065688820f1c94/fonttools-4.61.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e6cd0d9051b8ddaf7385f99dd82ec2a058e2b46cf1f1961e68e1ff20fcbb61af", size = 4999632 }, + { url = "https://files.pythonhosted.org/packages/5f/e0/19a2b86e54109b1d2ee8743c96a1d297238ae03243897bc5345c0365f34d/fonttools-4.61.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e074bc07c31406f45c418e17c1722e83560f181d122c412fa9e815df0ff74810", size = 4939438 }, + { url = "https://files.pythonhosted.org/packages/04/35/7b57a5f57d46286360355eff8d6b88c64ab6331107f37a273a71c803798d/fonttools-4.61.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5a9b78da5d5faa17e63b2404b77feeae105c1b7e75f26020ab7a27b76e02039f", size = 5088960 }, + { url = "https://files.pythonhosted.org/packages/3e/0e/6c5023eb2e0fe5d1ababc7e221e44acd3ff668781489cc1937a6f83d620a/fonttools-4.61.0-cp312-cp312-win32.whl", hash = "sha256:9821ed77bb676736b88fa87a737c97b6af06e8109667e625a4f00158540ce044", size = 2264404 }, + { url = "https://files.pythonhosted.org/packages/36/0b/63273128c7c5df19b1e4cd92e0a1e6ea5bb74a400c4905054c96ad60a675/fonttools-4.61.0-cp312-cp312-win_amd64.whl", hash = "sha256:0011d640afa61053bc6590f9a3394bd222de7cfde19346588beabac374e9d8ac", size = 2314427 }, + { url = "https://files.pythonhosted.org/packages/17/45/334f0d7f181e5473cfb757e1b60f4e60e7fc64f28d406e5d364a952718c0/fonttools-4.61.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba774b8cbd8754f54b8eb58124e8bd45f736b2743325ab1a5229698942b9b433", size = 2841801 }, + { url = "https://files.pythonhosted.org/packages/cc/63/97b9c78e1f79bc741d4efe6e51f13872d8edb2b36e1b9fb2bab0d4491bb7/fonttools-4.61.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c84b430616ed73ce46e9cafd0bf0800e366a3e02fb7e1ad7c1e214dbe3862b1f", size = 2379024 }, + { url = "https://files.pythonhosted.org/packages/4e/80/c87bc524a90dbeb2a390eea23eae448286983da59b7e02c67fa0ca96a8c5/fonttools-4.61.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b2b734d8391afe3c682320840c8191de9bd24e7eb85768dd4dc06ed1b63dbb1b", size = 4923706 }, + { url = "https://files.pythonhosted.org/packages/6d/f6/a3b0374811a1de8c3f9207ec88f61ad1bb96f938ed89babae26c065c2e46/fonttools-4.61.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5c5fff72bf31b0e558ed085e4fd7ed96eb85881404ecc39ed2a779e7cf724eb", size = 4979751 }, + { url = "https://files.pythonhosted.org/packages/a5/3b/30f63b4308b449091573285f9d27619563a84f399946bca3eadc9554afbe/fonttools-4.61.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:14a290c5c93fcab76b7f451e6a4b7721b712d90b3b5ed6908f1abcf794e90d6d", size = 4921113 }, + { url = "https://files.pythonhosted.org/packages/41/6c/58e6e9b7d9d8bf2d7010bd7bb493060b39b02a12d1cda64a8bfb116ce760/fonttools-4.61.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:13e3e20a5463bfeb77b3557d04b30bd6a96a6bb5c15c7b2e7908903e69d437a0", size = 5063183 }, + { url = "https://files.pythonhosted.org/packages/3f/e3/52c790ab2b07492df059947a1fd7778e105aac5848c0473029a4d20481a2/fonttools-4.61.0-cp313-cp313-win32.whl", hash = "sha256:6781e7a4bb010be1cd69a29927b0305c86b843395f2613bdabe115f7d6ea7f34", size = 2263159 }, + { url = "https://files.pythonhosted.org/packages/e9/1f/116013b200fbeba871046554d5d2a45fefa69a05c40e9cdfd0d4fff53edc/fonttools-4.61.0-cp313-cp313-win_amd64.whl", hash = "sha256:c53b47834ae41e8e4829171cc44fec0fdf125545a15f6da41776b926b9645a9a", size = 2313530 }, + { url = "https://files.pythonhosted.org/packages/d3/99/59b1e25987787cb714aa9457cee4c9301b7c2153f0b673e2b8679d37669d/fonttools-4.61.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:96dfc9bc1f2302224e48e6ee37e656eddbab810b724b52e9d9c13a57a6abad01", size = 2841429 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/4c1911d4332c8a144bb3b44416e274ccca0e297157c971ea1b3fbb855590/fonttools-4.61.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3b2065d94e5d63aafc2591c8b6ccbdb511001d9619f1bca8ad39b745ebeb5efa", size = 2378987 }, + { url = "https://files.pythonhosted.org/packages/24/b0/f442e90fde5d2af2ae0cb54008ab6411edc557ee33b824e13e1d04925ac9/fonttools-4.61.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e0d87e81e4d869549585ba0beb3f033718501c1095004f5e6aef598d13ebc216", size = 4873270 }, + { url = "https://files.pythonhosted.org/packages/bb/04/f5d5990e33053c8a59b90b1d7e10ad9b97a73f42c745304da0e709635fab/fonttools-4.61.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cfa2eb9bae650e58f0e8ad53c49d19a844d6034d6b259f30f197238abc1ccee", size = 4968270 }, + { url = "https://files.pythonhosted.org/packages/94/9f/2091402e0d27c9c8c4bab5de0e5cd146d9609a2d7d1c666bbb75c0011c1a/fonttools-4.61.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4238120002e68296d55e091411c09eab94e111c8ce64716d17df53fd0eb3bb3d", size = 4919799 }, + { url = "https://files.pythonhosted.org/packages/a8/72/86adab22fde710b829f8ffbc8f264df01928e5b7a8f6177fa29979ebf256/fonttools-4.61.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b6ceac262cc62bec01b3bb59abccf41b24ef6580869e306a4e88b7e56bb4bdda", size = 5030966 }, + { url = "https://files.pythonhosted.org/packages/e8/a7/7c8e31b003349e845b853f5e0a67b95ff6b052fa4f5224f8b72624f5ac69/fonttools-4.61.0-cp314-cp314-win32.whl", hash = "sha256:adbb4ecee1a779469a77377bbe490565effe8fce6fb2e6f95f064de58f8bac85", size = 2267243 }, + { url = "https://files.pythonhosted.org/packages/20/ee/f434fe7749360497c52b7dcbcfdbccdaab0a71c59f19d572576066717122/fonttools-4.61.0-cp314-cp314-win_amd64.whl", hash = "sha256:02bdf8e04d1a70476564b8640380f04bb4ac74edc1fc71f1bacb840b3e398ee9", size = 2318822 }, + { url = "https://files.pythonhosted.org/packages/33/b3/c16255320255e5c1863ca2b2599bb61a46e2f566db0bbb9948615a8fe692/fonttools-4.61.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:627216062d90ab0d98215176d8b9562c4dd5b61271d35f130bcd30f6a8aaa33a", size = 2924917 }, + { url = "https://files.pythonhosted.org/packages/e2/b8/08067ae21de705a817777c02ef36ab0b953cbe91d8adf134f9c2da75ed6d/fonttools-4.61.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7b446623c9cd5f14a59493818eaa80255eec2468c27d2c01b56e05357c263195", size = 2413576 }, + { url = "https://files.pythonhosted.org/packages/42/f1/96ff43f92addce2356780fdc203f2966206f3d22ea20e242c27826fd7442/fonttools-4.61.0-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:70e2a0c0182ee75e493ef33061bfebf140ea57e035481d2f95aa03b66c7a0e05", size = 4877447 }, + { url = "https://files.pythonhosted.org/packages/d0/1e/a3d8e51ed9ccfd7385e239ae374b78d258a0fb82d82cab99160a014a45d1/fonttools-4.61.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9064b0f55b947e929ac669af5311ab1f26f750214db6dd9a0c97e091e918f486", size = 5095681 }, + { url = "https://files.pythonhosted.org/packages/eb/f6/d256bd6c1065c146a0bdddf1c62f542e08ae5b3405dbf3fcc52be272f674/fonttools-4.61.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2cb5e45a824ce14b90510024d0d39dae51bd4fbb54c42a9334ea8c8cf4d95cbe", size = 4974140 }, + { url = "https://files.pythonhosted.org/packages/5d/0c/96633eb4b26f138cc48561c6e0c44b4ea48acea56b20b507d6b14f8e80ce/fonttools-4.61.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6e5ca8c62efdec7972dfdfd454415c4db49b89aeaefaaacada432f3b7eea9866", size = 5001741 }, + { url = "https://files.pythonhosted.org/packages/6f/9a/3b536bad3be4f26186f296e749ff17bad3e6d57232c104d752d24b2e265b/fonttools-4.61.0-cp314-cp314t-win32.whl", hash = "sha256:63c7125d31abe3e61d7bb917329b5543c5b3448db95f24081a13aaf064360fc8", size = 2330707 }, + { url = "https://files.pythonhosted.org/packages/18/ea/e6b9ac610451ee9f04477c311ad126de971f6112cb579fa391d2a8edb00b/fonttools-4.61.0-cp314-cp314t-win_amd64.whl", hash = "sha256:67d841aa272be5500de7f447c40d1d8452783af33b4c3599899319f6ef9ad3c1", size = 2395950 }, + { url = "https://files.pythonhosted.org/packages/0c/14/634f7daea5ffe6a5f7a0322ba8e1a0e23c9257b80aa91458107896d1dfc7/fonttools-4.61.0-py3-none-any.whl", hash = "sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635", size = 1144485 }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, +] + +[[package]] +name = "gridlock" +version = "2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "float-raster" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/a8/127949799dd8065e0360bfffe02a6f15a9f42a2dcd80a5789815f84882b8/gridlock-2.1.tar.gz", hash = "sha256:7d0ecf58a177767d40b76fc1147f758cefbe29dbc76456e678fcc9f32ce989c0", size = 40246 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/cf/b7986d89f781edc9439c29bb8c58676543517ad7d80f6af37c2be21199f3/gridlock-2.1-py3-none-any.whl", hash = "sha256:c8b5b3a6b1cd8516f66e7d7c5d3b7c306de3122ad8ec5811a30747f62056e4bd", size = 56795 }, +] + +[[package]] +name = "griffelib" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/82/74f4a3310cdabfbb10da554c3a672847f1ed33c6f61dd472681ce7f1fe67/griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e", size = 166461 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1", size = 142357 }, +] + +[[package]] +name = "htmlark" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/0a/c5150fb593abf13dd58ae3e3b46da56266d3f8aff8c0fc512f2001fa35a3/HTMLArk-1.0.0.tar.gz", hash = "sha256:1b19599371e30c04383c4aff2837ac326be689a6868e2867efb0414c2ddfe261", size = 9115 } + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167 }, + { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579 }, + { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309 }, + { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596 }, + { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548 }, + { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618 }, + { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437 }, + { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742 }, + { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810 }, + { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579 }, + { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071 }, + { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840 }, + { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159 }, + { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686 }, + { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460 }, + { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952 }, + { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756 }, + { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404 }, + { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410 }, + { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631 }, + { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963 }, + { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295 }, + { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987 }, + { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817 }, + { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895 }, + { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992 }, + { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681 }, + { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464 }, + { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961 }, + { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607 }, + { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546 }, + { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482 }, + { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720 }, + { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907 }, + { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334 }, + { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313 }, + { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970 }, + { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894 }, + { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995 }, + { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510 }, + { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903 }, + { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402 }, + { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135 }, + { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409 }, + { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763 }, + { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643 }, + { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818 }, + { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963 }, + { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639 }, + { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741 }, + { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646 }, + { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806 }, + { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605 }, + { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925 }, + { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414 }, + { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272 }, + { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578 }, + { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607 }, + { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150 }, + { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979 }, + { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456 }, + { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621 }, + { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417 }, + { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582 }, + { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514 }, + { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905 }, + { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399 }, + { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197 }, + { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125 }, + { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612 }, + { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990 }, + { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601 }, + { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041 }, + { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897 }, + { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835 }, + { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988 }, + { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260 }, + { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104 }, + { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592 }, + { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281 }, + { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009 }, + { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929 }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058 }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287 }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940 }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887 }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692 }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471 }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923 }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572 }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077 }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876 }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615 }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020 }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332 }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947 }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962 }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760 }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529 }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015 }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540 }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105 }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906 }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622 }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029 }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374 }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980 }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990 }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784 }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588 }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041 }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543 }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113 }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911 }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658 }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066 }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639 }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569 }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284 }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801 }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769 }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642 }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612 }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200 }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973 }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619 }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029 }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408 }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005 }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048 }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821 }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606 }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043 }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747 }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341 }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073 }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661 }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069 }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670 }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598 }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261 }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835 }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733 }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672 }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819 }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426 }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146 }, +] + +[[package]] +name = "matplotlib" +version = "3.10.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/86/de7e3a1cdcfc941483af70609edc06b83e7c8a0e0dc9ac325200a3f4d220/matplotlib-3.10.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6be43b667360fef5c754dda5d25a32e6307a03c204f3c0fc5468b78fa87b4160", size = 8251215 }, + { url = "https://files.pythonhosted.org/packages/fd/14/baad3222f424b19ce6ad243c71de1ad9ec6b2e4eb1e458a48fdc6d120401/matplotlib-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2b336e2d91a3d7006864e0990c83b216fcdca64b5a6484912902cef87313d78", size = 8139625 }, + { url = "https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efb30e3baaea72ce5928e32bab719ab4770099079d66726a62b11b1ef7273be4", size = 8712614 }, + { url = "https://files.pythonhosted.org/packages/5a/f4/b8347351da9a5b3f41e26cf547252d861f685c6867d179a7c9d60ad50189/matplotlib-3.10.8-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d56a1efd5bfd61486c8bc968fa18734464556f0fb8e51690f4ac25d85cbbbbc2", size = 9540997 }, + { url = "https://files.pythonhosted.org/packages/9e/c0/c7b914e297efe0bc36917bf216b2acb91044b91e930e878ae12981e461e5/matplotlib-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238b7ce5717600615c895050239ec955d91f321c209dd110db988500558e70d6", size = 9596825 }, + { url = "https://files.pythonhosted.org/packages/6f/d3/a4bbc01c237ab710a1f22b4da72f4ff6d77eb4c7735ea9811a94ae239067/matplotlib-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:18821ace09c763ec93aef5eeff087ee493a24051936d7b9ebcad9662f66501f9", size = 8135090 }, + { url = "https://files.pythonhosted.org/packages/89/dd/a0b6588f102beab33ca6f5218b31725216577b2a24172f327eaf6417d5c9/matplotlib-3.10.8-cp311-cp311-win_arm64.whl", hash = "sha256:bab485bcf8b1c7d2060b4fcb6fc368a9e6f4cd754c9c2fea281f4be21df394a2", size = 8012377 }, + { url = "https://files.pythonhosted.org/packages/9e/67/f997cdcbb514012eb0d10cd2b4b332667997fb5ebe26b8d41d04962fa0e6/matplotlib-3.10.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:64fcc24778ca0404ce0cb7b6b77ae1f4c7231cdd60e6778f999ee05cbd581b9a", size = 8260453 }, + { url = "https://files.pythonhosted.org/packages/7e/65/07d5f5c7f7c994f12c768708bd2e17a4f01a2b0f44a1c9eccad872433e2e/matplotlib-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9a5ca4ac220a0cdd1ba6bcba3608547117d30468fefce49bb26f55c1a3d5c58", size = 8148321 }, + { url = "https://files.pythonhosted.org/packages/3e/f3/c5195b1ae57ef85339fd7285dfb603b22c8b4e79114bae5f4f0fcf688677/matplotlib-3.10.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ab4aabc72de4ff77b3ec33a6d78a68227bf1123465887f9905ba79184a1cc04", size = 8716944 }, + { url = "https://files.pythonhosted.org/packages/00/f9/7638f5cc82ec8a7aa005de48622eecc3ed7c9854b96ba15bd76b7fd27574/matplotlib-3.10.8-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24d50994d8c5816ddc35411e50a86ab05f575e2530c02752e02538122613371f", size = 9550099 }, + { url = "https://files.pythonhosted.org/packages/57/61/78cd5920d35b29fd2a0fe894de8adf672ff52939d2e9b43cb83cd5ce1bc7/matplotlib-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99eefd13c0dc3b3c1b4d561c1169e65fe47aab7b8158754d7c084088e2329466", size = 9613040 }, + { url = "https://files.pythonhosted.org/packages/30/4e/c10f171b6e2f44d9e3a2b96efa38b1677439d79c99357600a62cc1e9594e/matplotlib-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:dd80ecb295460a5d9d260df63c43f4afbdd832d725a531f008dad1664f458adf", size = 8142717 }, + { url = "https://files.pythonhosted.org/packages/f1/76/934db220026b5fef85f45d51a738b91dea7d70207581063cd9bd8fafcf74/matplotlib-3.10.8-cp312-cp312-win_arm64.whl", hash = "sha256:3c624e43ed56313651bc18a47f838b60d7b8032ed348911c54906b130b20071b", size = 8012751 }, + { url = "https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3f2e409836d7f5ac2f1c013110a4d50b9f7edc26328c108915f9075d7d7a91b6", size = 8261076 }, + { url = "https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56271f3dac49a88d7fca5060f004d9d22b865f743a12a23b1e937a0be4818ee1", size = 8148794 }, + { url = "https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a0a7f52498f72f13d4a25ea70f35f4cb60642b466cbb0a9be951b5bc3f45a486", size = 8718474 }, + { url = "https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:646d95230efb9ca614a7a594d4fcacde0ac61d25e37dd51710b36477594963ce", size = 9549637 }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8dc289776eae5109e268c4fb92baf870678dc048a25d4ac903683b86d5bf/matplotlib-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f89c151aab2e2e23cb3fe0acad1e8b82841fd265379c4cecd0f3fcb34c15e0f6", size = 9613678 }, + { url = "https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:e8ea3e2d4066083e264e75c829078f9e149fa119d27e19acd503de65e0b13149", size = 8142686 }, + { url = "https://files.pythonhosted.org/packages/66/52/8d8a8730e968185514680c2a6625943f70269509c3dcfc0dcf7d75928cb8/matplotlib-3.10.8-cp313-cp313-win_arm64.whl", hash = "sha256:c108a1d6fa78a50646029cb6d49808ff0fc1330fda87fa6f6250c6b5369b6645", size = 8012917 }, + { url = "https://files.pythonhosted.org/packages/b5/27/51fe26e1062f298af5ef66343d8ef460e090a27fea73036c76c35821df04/matplotlib-3.10.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ad3d9833a64cf48cc4300f2b406c3d0f4f4724a91c0bd5640678a6ba7c102077", size = 8305679 }, + { url = "https://files.pythonhosted.org/packages/2c/1e/4de865bc591ac8e3062e835f42dd7fe7a93168d519557837f0e37513f629/matplotlib-3.10.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:eb3823f11823deade26ce3b9f40dcb4a213da7a670013929f31d5f5ed1055b22", size = 8198336 }, + { url = "https://files.pythonhosted.org/packages/c6/cb/2f7b6e75fb4dce87ef91f60cac4f6e34f4c145ab036a22318ec837971300/matplotlib-3.10.8-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d9050fee89a89ed57b4fb2c1bfac9a3d0c57a0d55aed95949eedbc42070fea39", size = 8731653 }, + { url = "https://files.pythonhosted.org/packages/46/b3/bd9c57d6ba670a37ab31fb87ec3e8691b947134b201f881665b28cc039ff/matplotlib-3.10.8-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b44d07310e404ba95f8c25aa5536f154c0a8ec473303535949e52eb71d0a1565", size = 9561356 }, + { url = "https://files.pythonhosted.org/packages/c0/3d/8b94a481456dfc9dfe6e39e93b5ab376e50998cddfd23f4ae3b431708f16/matplotlib-3.10.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0a33deb84c15ede243aead39f77e990469fff93ad1521163305095b77b72ce4a", size = 9614000 }, + { url = "https://files.pythonhosted.org/packages/bd/cd/bc06149fe5585ba800b189a6a654a75f1f127e8aab02fd2be10df7fa500c/matplotlib-3.10.8-cp313-cp313t-win_amd64.whl", hash = "sha256:3a48a78d2786784cc2413e57397981fb45c79e968d99656706018d6e62e57958", size = 8220043 }, + { url = "https://files.pythonhosted.org/packages/e3/de/b22cf255abec916562cc04eef457c13e58a1990048de0c0c3604d082355e/matplotlib-3.10.8-cp313-cp313t-win_arm64.whl", hash = "sha256:15d30132718972c2c074cd14638c7f4592bd98719e2308bccea40e0538bc0cb5", size = 8062075 }, + { url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481 }, + { url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473 }, + { url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896 }, + { url = "https://files.pythonhosted.org/packages/f5/26/4221a741eb97967bc1fd5e4c52b9aa5a91b2f4ec05b59f6def4d820f9df9/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008", size = 9824193 }, + { url = "https://files.pythonhosted.org/packages/1f/f3/3abf75f38605772cf48a9daf5821cd4f563472f38b4b828c6fba6fa6d06e/matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c", size = 9615444 }, + { url = "https://files.pythonhosted.org/packages/93/a5/de89ac80f10b8dc615807ee1133cd99ac74082581196d4d9590bea10690d/matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11", size = 8272719 }, + { url = "https://files.pythonhosted.org/packages/69/ce/b006495c19ccc0a137b48083168a37bd056392dee02f87dba0472f2797fe/matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8", size = 8144205 }, + { url = "https://files.pythonhosted.org/packages/68/d9/b31116a3a855bd313c6fcdb7226926d59b041f26061c6c5b1be66a08c826/matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50", size = 8305785 }, + { url = "https://files.pythonhosted.org/packages/1e/90/6effe8103f0272685767ba5f094f453784057072f49b393e3ea178fe70a5/matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908", size = 8198361 }, + { url = "https://files.pythonhosted.org/packages/d7/65/a73188711bea603615fc0baecca1061429ac16940e2385433cc778a9d8e7/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a", size = 9561357 }, + { url = "https://files.pythonhosted.org/packages/f4/3d/b5c5d5d5be8ce63292567f0e2c43dde9953d3ed86ac2de0a72e93c8f07a1/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1", size = 9823610 }, + { url = "https://files.pythonhosted.org/packages/4d/4b/e7beb6bbd49f6bae727a12b270a2654d13c397576d25bd6786e47033300f/matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c", size = 9614011 }, + { url = "https://files.pythonhosted.org/packages/7c/e6/76f2813d31f032e65f6f797e3f2f6e4aab95b65015924b1c51370395c28a/matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b", size = 8362801 }, + { url = "https://files.pythonhosted.org/packages/5d/49/d651878698a0b67f23aa28e17f45a6d6dd3d3f933fa29087fa4ce5947b5a/matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f", size = 8192560 }, + { url = "https://files.pythonhosted.org/packages/04/30/3afaa31c757f34b7725ab9d2ba8b48b5e89c2019c003e7d0ead143aabc5a/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6da7c2ce169267d0d066adcf63758f0604aa6c3eebf67458930f9d9b79ad1db1", size = 8249198 }, + { url = "https://files.pythonhosted.org/packages/48/2f/6334aec331f57485a642a7c8be03cb286f29111ae71c46c38b363230063c/matplotlib-3.10.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9153c3292705be9f9c64498a8872118540c3f4123d1a1c840172edf262c8be4a", size = 8136817 }, + { url = "https://files.pythonhosted.org/packages/73/e4/6d6f14b2a759c622f191b2d67e9075a3f56aaccb3be4bb9bb6890030d0a0/matplotlib-3.10.8-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ae029229a57cd1e8fe542485f27e7ca7b23aa9e8944ddb4985d0bc444f1eca2", size = 8713867 }, +] + +[[package]] +name = "meanas" +source = { editable = "." } +dependencies = [ + { name = "gridlock" }, + { name = "numpy" }, + { name = "scipy" }, +] + +[package.optional-dependencies] +dev = [ + { name = "coverage" }, + { name = "htmlark" }, + { name = "matplotlib" }, + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "mkdocs-print-site-plugin" }, + { name = "mkdocstrings", extra = ["python"] }, + { name = "pymdown-extensions" }, + { name = "pytest" }, + { name = "ruff" }, + { name = "scikit-rf" }, +] +docs = [ + { name = "htmlark" }, + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "mkdocs-print-site-plugin" }, + { name = "mkdocstrings", extra = ["python"] }, + { name = "pymdown-extensions" }, + { name = "ruff" }, +] +examples = [ + { name = "matplotlib" }, + { name = "scikit-rf" }, +] +test = [ + { name = "coverage" }, + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "coverage", marker = "extra == 'dev'" }, + { name = "coverage", marker = "extra == 'test'" }, + { name = "gridlock", specifier = ">=2.1" }, + { name = "htmlark", marker = "extra == 'dev'", specifier = ">=1.0" }, + { name = "htmlark", marker = "extra == 'docs'", specifier = ">=1.0" }, + { name = "matplotlib", marker = "extra == 'dev'", specifier = ">=3.10.8" }, + { name = "matplotlib", marker = "extra == 'examples'", specifier = ">=3.10.8" }, + { name = "mkdocs", marker = "extra == 'dev'", specifier = ">=1.6" }, + { name = "mkdocs", marker = "extra == 'docs'", specifier = ">=1.6" }, + { name = "mkdocs-material", marker = "extra == 'dev'", specifier = ">=9.5" }, + { name = "mkdocs-material", marker = "extra == 'docs'", specifier = ">=9.5" }, + { name = "mkdocs-print-site-plugin", marker = "extra == 'dev'", specifier = ">=2.3" }, + { name = "mkdocs-print-site-plugin", marker = "extra == 'docs'", specifier = ">=2.3" }, + { name = "mkdocstrings", extras = ["python"], marker = "extra == 'dev'", specifier = ">=0.25" }, + { name = "mkdocstrings", extras = ["python"], marker = "extra == 'docs'", specifier = ">=0.25" }, + { name = "numpy", specifier = ">=2.0" }, + { name = "pymdown-extensions", marker = "extra == 'dev'", specifier = ">=10.7" }, + { name = "pymdown-extensions", marker = "extra == 'docs'", specifier = ">=10.7" }, + { name = "pytest", marker = "extra == 'dev'" }, + { name = "pytest", marker = "extra == 'test'" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" }, + { name = "ruff", marker = "extra == 'docs'", specifier = ">=0.6" }, + { name = "scikit-rf", marker = "extra == 'dev'", specifier = ">=1.0" }, + { name = "scikit-rf", marker = "extra == 'examples'", specifier = ">=1.0" }, + { name = "scipy", specifier = "~=1.14" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451 }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530 }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555 }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/29/6d2bcf41ae40802c4beda2432396fff97b8456fb496371d1bc7aad6512ec/mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69", size = 4097959 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/01/bc663630c510822c95c47a66af9fa7a443c295b47d5f041e5e6ae62ef659/mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba", size = 9305470 }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728 }, +] + +[[package]] +name = "mkdocs-print-site-plugin" +version = "2.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs-material" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/18/5c71f48b83191fb30cc58617fea20f56647eaa6cafd06a7fb34c738c5acb/mkdocs_print_site_plugin-2.8.tar.gz", hash = "sha256:ab1c89cdb468352975e3bb3bb0ef25dcc2bb88931b03f173206dc95ab02f843f", size = 231688 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/3e/7513f2f37c563da65d1b91781e047f4a1c0ceac8206d4f6042428428e4ad/mkdocs_print_site_plugin-2.8-py3-none-any.whl", hash = "sha256:838bd0a9b7141c11c0f1fdaa51ffe70c35740bec1f07c0806f8018e92f93f9da", size = 21477 }, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/5d/f888d4d3eb31359b327bc9b17a212d6ef03fe0b0682fbb3fc2cb849fb12b/mkdocstrings-1.0.4.tar.gz", hash = "sha256:3969a6515b77db65fd097b53c1b7aa4ae840bd71a2ee62a6a3e89503446d7172", size = 100088 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl", hash = "sha256:63464b4b29053514f32a1dbbf604e52876d5e638111b0c295ab7ed3cac73ca9b", size = 35560 }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/33/c225eaf898634bdda489a6766fc35d1683c640bffe0e0acd10646b13536d/mkdocstrings_python-2.0.3.tar.gz", hash = "sha256:c518632751cc869439b31c9d3177678ad2bfa5c21b79b863956ad68fc92c13b8", size = 199083 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/28/79f0f8de97cce916d5ae88a7bee1ad724855e83e6019c0b4d5b3fabc80f3/mkdocstrings_python-2.0.3-py3-none-any.whl", hash = "sha256:0b83513478bdfd803ff05aa43e9b1fca9dd22bcd9471f09ca6257f009bc5ee12", size = 104779 }, +] + +[[package]] +name = "numpy" +version = "2.3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641 }, + { url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324 }, + { url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872 }, + { url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148 }, + { url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282 }, + { url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903 }, + { url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672 }, + { url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896 }, + { url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608 }, + { url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442 }, + { url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555 }, + { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873 }, + { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838 }, + { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378 }, + { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559 }, + { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702 }, + { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086 }, + { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985 }, + { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976 }, + { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274 }, + { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922 }, + { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667 }, + { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251 }, + { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652 }, + { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172 }, + { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990 }, + { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902 }, + { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430 }, + { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551 }, + { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275 }, + { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637 }, + { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090 }, + { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710 }, + { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292 }, + { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391 }, + { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275 }, + { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855 }, + { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359 }, + { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374 }, + { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587 }, + { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940 }, + { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341 }, + { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507 }, + { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706 }, + { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507 }, + { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049 }, + { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603 }, + { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696 }, + { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350 }, + { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190 }, + { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749 }, + { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432 }, + { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388 }, + { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651 }, + { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503 }, + { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612 }, + { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042 }, + { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502 }, + { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962 }, + { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054 }, + { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613 }, + { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147 }, + { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806 }, + { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760 }, + { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459 }, + { url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689 }, + { url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053 }, + { url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635 }, + { url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770 }, + { url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768 }, + { url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263 }, + { url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213 }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746 }, +] + +[[package]] +name = "pandas" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/99/b342345300f13440fe9fe385c3c481e2d9a595ee3bab4d3219247ac94e9a/pandas-3.0.2.tar.gz", hash = "sha256:f4753e73e34c8d83221ba58f232433fca2748be8b18dbca02d242ed153945043", size = 4645855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/35/6411db530c618e0e0005187e35aa02ce60ae4c4c4d206964a2f978217c27/pandas-3.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a727a73cbdba2f7458dc82449e2315899d5140b449015d822f515749a46cbbe0", size = 10326926 }, + { url = "https://files.pythonhosted.org/packages/c4/d3/b7da1d5d7dbdc5ef52ed7debd2b484313b832982266905315dad5a0bf0b1/pandas-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbbd4aa20ca51e63b53bbde6a0fa4254b1aaabb74d2f542df7a7959feb1d760c", size = 9926987 }, + { url = "https://files.pythonhosted.org/packages/52/77/9b1c2d6070b5dbe239a7bc889e21bfa58720793fb902d1e070695d87c6d0/pandas-3.0.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:339dda302bd8369dedeae979cb750e484d549b563c3f54f3922cb8ff4978c5eb", size = 10757067 }, + { url = "https://files.pythonhosted.org/packages/20/17/ec40d981705654853726e7ac9aea9ddbb4a5d9cf54d8472222f4f3de06c2/pandas-3.0.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:61c2fd96d72b983a9891b2598f286befd4ad262161a609c92dc1652544b46b76", size = 11258787 }, + { url = "https://files.pythonhosted.org/packages/90/e3/3f1126d43d3702ca8773871a81c9f15122a1f412342cc56284ffda5b1f70/pandas-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c934008c733b8bbea273ea308b73b3156f0181e5b72960790b09c18a2794fe1e", size = 11771616 }, + { url = "https://files.pythonhosted.org/packages/2e/cf/0f4e268e1f5062e44a6bda9f925806721cd4c95c2b808a4c82ebe914f96b/pandas-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:60a80bb4feacbef5e1447a3f82c33209c8b7e07f28d805cfd1fb951e5cb443aa", size = 12337623 }, + { url = "https://files.pythonhosted.org/packages/44/a0/97a6339859d4acb2536efb24feb6708e82f7d33b2ed7e036f2983fcced82/pandas-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:ed72cb3f45190874eb579c64fa92d9df74e98fd63e2be7f62bce5ace0ade61df", size = 9897372 }, + { url = "https://files.pythonhosted.org/packages/8f/eb/781516b808a99ddf288143cec46b342b3016c3414d137da1fdc3290d8860/pandas-3.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:f12b1a9e332c01e09510586f8ca9b108fd631fd656af82e452d7315ef6df5f9f", size = 9154922 }, + { url = "https://files.pythonhosted.org/packages/f3/b0/c20bd4d6d3f736e6bd6b55794e9cd0a617b858eaad27c8f410ea05d953b7/pandas-3.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:232a70ebb568c0c4d2db4584f338c1577d81e3af63292208d615907b698a0f18", size = 10347921 }, + { url = "https://files.pythonhosted.org/packages/35/d0/4831af68ce30cc2d03c697bea8450e3225a835ef497d0d70f31b8cdde965/pandas-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:970762605cff1ca0d3f71ed4f3a769ea8f85fc8e6348f6e110b8fea7e6eb5a14", size = 9888127 }, + { url = "https://files.pythonhosted.org/packages/61/a9/16ea9346e1fc4a96e2896242d9bc674764fb9049b0044c0132502f7a771e/pandas-3.0.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aff4e6f4d722e0652707d7bcb190c445fe58428500c6d16005b02401764b1b3d", size = 10399577 }, + { url = "https://files.pythonhosted.org/packages/c4/a8/3a61a721472959ab0ce865ef05d10b0d6bfe27ce8801c99f33d4fa996e65/pandas-3.0.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef8b27695c3d3dc78403c9a7d5e59a62d5464a7e1123b4e0042763f7104dc74f", size = 10880030 }, + { url = "https://files.pythonhosted.org/packages/da/65/7225c0ea4d6ce9cb2160a7fb7f39804871049f016e74782e5dade4d14109/pandas-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f8d68083e49e16b84734eb1a4dcae4259a75c90fb6e2251ab9a00b61120c06ab", size = 11409468 }, + { url = "https://files.pythonhosted.org/packages/fa/5b/46e7c76032639f2132359b5cf4c785dd8cf9aea5ea64699eac752f02b9db/pandas-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:32cc41f310ebd4a296d93515fcac312216adfedb1894e879303987b8f1e2b97d", size = 11936381 }, + { url = "https://files.pythonhosted.org/packages/7b/8b/721a9cff6fa6a91b162eb51019c6243b82b3226c71bb6c8ef4a9bd65cbc6/pandas-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:a4785e1d6547d8427c5208b748ae2efb64659a21bd82bf440d4262d02bfa02a4", size = 9744993 }, + { url = "https://files.pythonhosted.org/packages/d5/18/7f0bd34ae27b28159aa80f2a6799f47fda34f7fb938a76e20c7b7fe3b200/pandas-3.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:08504503f7101300107ecdc8df73658e4347586db5cfdadabc1592e9d7e7a0fd", size = 9056118 }, + { url = "https://files.pythonhosted.org/packages/bf/ca/3e639a1ea6fcd0617ca4e8ca45f62a74de33a56ae6cd552735470b22c8d3/pandas-3.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5918ba197c951dec132b0c5929a00c0bf05d5942f590d3c10a807f6e15a57d3", size = 10321105 }, + { url = "https://files.pythonhosted.org/packages/0b/77/dbc82ff2fb0e63c6564356682bf201edff0ba16c98630d21a1fb312a8182/pandas-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d606a041c89c0a474a4702d532ab7e73a14fe35c8d427b972a625c8e46373668", size = 9864088 }, + { url = "https://files.pythonhosted.org/packages/5c/2b/341f1b04bbca2e17e13cd3f08c215b70ef2c60c5356ef1e8c6857449edc7/pandas-3.0.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:710246ba0616e86891b58ab95f2495143bb2bc83ab6b06747c74216f583a6ac9", size = 10369066 }, + { url = "https://files.pythonhosted.org/packages/12/c5/cbb1ffefb20a93d3f0e1fdcda699fb84976210d411b008f97f48bf6ce27e/pandas-3.0.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d3cfe227c725b1f3dff4278b43d8c784656a42a9325b63af6b1492a8232209e", size = 10876780 }, + { url = "https://files.pythonhosted.org/packages/98/fe/2249ae5e0a69bd0ddf17353d0a5d26611d70970111f5b3600cdc8be883e7/pandas-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c3b723df9087a9a9a840e263ebd9f88b64a12075d1bf2ea401a5a42f254f084d", size = 11375181 }, + { url = "https://files.pythonhosted.org/packages/de/64/77a38b09e70b6464883b8d7584ab543e748e42c1b5d337a2ee088e0df741/pandas-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3096110bf9eac0070b7208465f2740e2d8a670d5cb6530b5bb884eca495fd39", size = 11928899 }, + { url = "https://files.pythonhosted.org/packages/5e/52/42855bf626868413f761addd574acc6195880ae247a5346477a4361c3acb/pandas-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:07a10f5c36512eead51bc578eb3354ad17578b22c013d89a796ab5eee90cd991", size = 9746574 }, + { url = "https://files.pythonhosted.org/packages/88/39/21304ae06a25e8bf9fc820d69b29b2c495b2ae580d1e143146c309941760/pandas-3.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:5fdbfa05931071aba28b408e59226186b01eb5e92bea2ab78b65863ca3228d84", size = 9047156 }, + { url = "https://files.pythonhosted.org/packages/72/20/7defa8b27d4f330a903bb68eea33be07d839c5ea6bdda54174efcec0e1d2/pandas-3.0.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:dbc20dea3b9e27d0e66d74c42b2d0c1bed9c2ffe92adea33633e3bedeb5ac235", size = 10756238 }, + { url = "https://files.pythonhosted.org/packages/e9/95/49433c14862c636afc0e9b2db83ff16b3ad92959364e52b2955e44c8e94c/pandas-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b75c347eff42497452116ce05ef461822d97ce5b9ff8df6edacb8076092c855d", size = 10408520 }, + { url = "https://files.pythonhosted.org/packages/3b/f8/462ad2b5881d6b8ec8e5f7ed2ea1893faa02290d13870a1600fe72ad8efc/pandas-3.0.2-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1478075142e83a5571782ad007fb201ed074bdeac7ebcc8890c71442e96adf7", size = 10324154 }, + { url = "https://files.pythonhosted.org/packages/0a/65/d1e69b649cbcddda23ad6e4c40ef935340f6f652a006e5cbc3555ac8adb3/pandas-3.0.2-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5880314e69e763d4c8b27937090de570f1fb8d027059a7ada3f7f8e98bdcb677", size = 10714449 }, + { url = "https://files.pythonhosted.org/packages/47/a4/85b59bc65b8190ea3689882db6cdf32a5003c0ccd5a586c30fdcc3ffc4fc/pandas-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b5329e26898896f06035241a626d7c335daa479b9bbc82be7c2742d048e41172", size = 11338475 }, + { url = "https://files.pythonhosted.org/packages/1e/c4/bc6966c6e38e5d9478b935272d124d80a589511ed1612a5d21d36f664c68/pandas-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:81526c4afd31971f8b62671442a4b2b51e0aa9acc3819c9f0f12a28b6fcf85f1", size = 11786568 }, + { url = "https://files.pythonhosted.org/packages/e8/74/09298ca9740beed1d3504e073d67e128aa07e5ca5ca2824b0c674c0b8676/pandas-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:7cadd7e9a44ec13b621aec60f9150e744cfc7a3dd32924a7e2f45edff31823b0", size = 10488652 }, + { url = "https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:db0dbfd2a6cdf3770aa60464d50333d8f3d9165b2f2671bcc299b72de5a6677b", size = 10326084 }, + { url = "https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0555c5882688a39317179ab4a0ed41d3ebc8812ab14c69364bbee8fb7a3f6288", size = 9914146 }, + { url = "https://files.pythonhosted.org/packages/8d/77/3a227ff3337aa376c60d288e1d61c5d097131d0ac71f954d90a8f369e422/pandas-3.0.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01f31a546acd5574ef77fe199bc90b55527c225c20ccda6601cf6b0fd5ed597c", size = 10444081 }, + { url = "https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:deeca1b5a931fdf0c2212c8a659ade6d3b1edc21f0914ce71ef24456ca7a6535", size = 10897535 }, + { url = "https://files.pythonhosted.org/packages/06/9d/98cc7a7624f7932e40f434299260e2917b090a579d75937cb8a57b9d2de3/pandas-3.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f48afd9bb13300ffb5a3316973324c787054ba6665cda0da3fbd67f451995db", size = 11446992 }, + { url = "https://files.pythonhosted.org/packages/9a/cd/19ff605cc3760e80602e6826ddef2824d8e7050ed80f2e11c4b079741dc3/pandas-3.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6c4d8458b97a35717b62469a4ea0e85abd5ed8687277f5ccfc67f8a5126f8c53", size = 11968257 }, + { url = "https://files.pythonhosted.org/packages/db/60/aba6a38de456e7341285102bede27514795c1eaa353bc0e7638b6b785356/pandas-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:b35d14bb5d8285d9494fe93815a9e9307c0876e10f1e8e89ac5b88f728ec8dcf", size = 9865893 }, + { url = "https://files.pythonhosted.org/packages/08/71/e5ec979dd2e8a093dacb8864598c0ff59a0cee0bbcdc0bfec16a51684d4f/pandas-3.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:63d141b56ef686f7f0d714cfb8de4e320475b86bf4b620aa0b7da89af8cbdbbb", size = 9188644 }, + { url = "https://files.pythonhosted.org/packages/f1/6c/7b45d85db19cae1eb524f2418ceaa9d85965dcf7b764ed151386b7c540f0/pandas-3.0.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:140f0cffb1fa2524e874dde5b477d9defe10780d8e9e220d259b2c0874c89d9d", size = 10776246 }, + { url = "https://files.pythonhosted.org/packages/a8/3e/7b00648b086c106e81766f25322b48aa8dfa95b55e621dbdf2fdd413a117/pandas-3.0.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae37e833ff4fed0ba352f6bdd8b73ba3ab3256a85e54edfd1ab51ae40cca0af8", size = 10424801 }, + { url = "https://files.pythonhosted.org/packages/da/6e/558dd09a71b53b4008e7fc8a98ec6d447e9bfb63cdaeea10e5eb9b2dabe8/pandas-3.0.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d888a5c678a419a5bb41a2a93818e8ed9fd3172246555c0b37b7cc27027effd", size = 10345643 }, + { url = "https://files.pythonhosted.org/packages/be/e3/921c93b4d9a280409451dc8d07b062b503bbec0531d2627e73a756e99a82/pandas-3.0.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b444dc64c079e84df91baa8bf613d58405645461cabca929d9178f2cd392398d", size = 10743641 }, + { url = "https://files.pythonhosted.org/packages/56/ca/fd17286f24fa3b4d067965d8d5d7e14fe557dd4f979a0b068ac0deaf8228/pandas-3.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4544c7a54920de8eeacaa1466a6b7268ecfbc9bc64ab4dbb89c6bbe94d5e0660", size = 11361993 }, + { url = "https://files.pythonhosted.org/packages/e4/a5/2f6ed612056819de445a433ca1f2821ac3dab7f150d569a59e9cc105de1d/pandas-3.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:734be7551687c00fbd760dc0522ed974f82ad230d4a10f54bf51b80d44a08702", size = 11815274 }, + { url = "https://files.pythonhosted.org/packages/00/2f/b622683e99ec3ce00b0854bac9e80868592c5b051733f2cf3a868e5fea26/pandas-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:57a07209bebcbcf768d2d13c9b78b852f9a15978dac41b9e6421a81ad4cdd276", size = 10888530 }, + { url = "https://files.pythonhosted.org/packages/cb/2b/f8434233fab2bd66a02ec014febe4e5adced20e2693e0e90a07d118ed30e/pandas-3.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:5371b72c2d4d415d08765f32d689217a43227484e81b2305b52076e328f6f482", size = 9455341 }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206 }, +] + +[[package]] +name = "pillow" +version = "12.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798 }, + { url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589 }, + { url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472 }, + { url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887 }, + { url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964 }, + { url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756 }, + { url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075 }, + { url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955 }, + { url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440 }, + { url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256 }, + { url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025 }, + { url = "https://files.pythonhosted.org/packages/2c/90/4fcce2c22caf044e660a198d740e7fbc14395619e3cb1abad12192c0826c/pillow-12.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371", size = 5249377 }, + { url = "https://files.pythonhosted.org/packages/fd/e0/ed960067543d080691d47d6938ebccbf3976a931c9567ab2fbfab983a5dd/pillow-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082", size = 4650343 }, + { url = "https://files.pythonhosted.org/packages/e7/a1/f81fdeddcb99c044bf7d6faa47e12850f13cee0849537a7d27eeab5534d4/pillow-12.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f", size = 6232981 }, + { url = "https://files.pythonhosted.org/packages/88/e1/9098d3ce341a8750b55b0e00c03f1630d6178f38ac191c81c97a3b047b44/pillow-12.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d", size = 8041399 }, + { url = "https://files.pythonhosted.org/packages/a7/62/a22e8d3b602ae8cc01446d0c57a54e982737f44b6f2e1e019a925143771d/pillow-12.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953", size = 6347740 }, + { url = "https://files.pythonhosted.org/packages/4f/87/424511bdcd02c8d7acf9f65caa09f291a519b16bd83c3fb3374b3d4ae951/pillow-12.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8", size = 7040201 }, + { url = "https://files.pythonhosted.org/packages/dc/4d/435c8ac688c54d11755aedfdd9f29c9eeddf68d150fe42d1d3dbd2365149/pillow-12.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79", size = 6462334 }, + { url = "https://files.pythonhosted.org/packages/2b/f2/ad34167a8059a59b8ad10bc5c72d4d9b35acc6b7c0877af8ac885b5f2044/pillow-12.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba", size = 7134162 }, + { url = "https://files.pythonhosted.org/packages/0c/b1/a7391df6adacf0a5c2cf6ac1cf1fcc1369e7d439d28f637a847f8803beb3/pillow-12.0.0-cp312-cp312-win32.whl", hash = "sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0", size = 6298769 }, + { url = "https://files.pythonhosted.org/packages/a2/0b/d87733741526541c909bbf159e338dcace4f982daac6e5a8d6be225ca32d/pillow-12.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a", size = 7001107 }, + { url = "https://files.pythonhosted.org/packages/bc/96/aaa61ce33cc98421fb6088af2a03be4157b1e7e0e87087c888e2370a7f45/pillow-12.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad", size = 2436012 }, + { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493 }, + { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461 }, + { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912 }, + { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132 }, + { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099 }, + { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808 }, + { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804 }, + { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553 }, + { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729 }, + { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789 }, + { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917 }, + { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391 }, + { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477 }, + { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918 }, + { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406 }, + { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218 }, + { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564 }, + { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260 }, + { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248 }, + { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043 }, + { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915 }, + { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998 }, + { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201 }, + { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165 }, + { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834 }, + { url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531 }, + { url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554 }, + { url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812 }, + { url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689 }, + { url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186 }, + { url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308 }, + { url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222 }, + { url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657 }, + { url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482 }, + { url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416 }, + { url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584 }, + { url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621 }, + { url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916 }, + { url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836 }, + { url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092 }, + { url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158 }, + { url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882 }, + { url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001 }, + { url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146 }, + { url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344 }, + { url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864 }, + { url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911 }, + { url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045 }, + { url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282 }, + { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630 }, + { url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068 }, + { url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994 }, + { url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639 }, + { url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839 }, + { url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505 }, + { url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654 }, + { url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850 }, +] + +[[package]] +name = "platformdirs" +version = "4.9.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348 }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.21.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/08/f1c908c581fd11913da4711ea7ba32c0eee40b0190000996bb863b0c9349/pymdown_extensions-10.21.2.tar.gz", hash = "sha256:c3f55a5b8a1d0edf6699e35dcbea71d978d34ff3fa79f3d807b8a5b3fa90fbdc", size = 853922 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/27/a2fc51a4a122dfd1015e921ae9d22fee3d20b0b8080d9a704578bf9deece/pymdown_extensions-10.21.2-py3-none-any.whl", hash = "sha256:5c0fd2a2bea14eb39af8ff284f1066d898ab2187d81b889b75d46d4348c01638", size = 268901 }, +] + +[[package]] +name = "pyparsing" +version = "3.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890 }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826 }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577 }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556 }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114 }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638 }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463 }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986 }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543 }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763 }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669 }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252 }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081 }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159 }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626 }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613 }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115 }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814 }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809 }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454 }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355 }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175 }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228 }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194 }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108 }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641 }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901 }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132 }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261 }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272 }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923 }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722 }, +] + +[[package]] +name = "requests" +version = "2.33.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947 }, +] + +[[package]] +name = "ruff" +version = "0.15.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/8d/192f3d7103816158dfd5ea50d098ef2aec19194e6cbccd4b3485bdb2eb2d/ruff-0.15.11.tar.gz", hash = "sha256:f092b21708bf0e7437ce9ada249dfe688ff9a0954fc94abab05dcea7dcd29c33", size = 4637264 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/1e/6aca3427f751295ab011828e15e9bf452200ac74484f1db4be0197b8170b/ruff-0.15.11-py3-none-linux_armv6l.whl", hash = "sha256:e927cfff503135c558eb581a0c9792264aae9507904eb27809cdcff2f2c847b7", size = 10607943 }, + { url = "https://files.pythonhosted.org/packages/e7/26/1341c262e74f36d4e84f3d6f4df0ac68cd53331a66bfc5080daa17c84c0b/ruff-0.15.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7a1b5b2938d8f890b76084d4fa843604d787a912541eae85fd7e233398bbb73e", size = 10988592 }, + { url = "https://files.pythonhosted.org/packages/03/71/850b1d6ffa9564fbb6740429bad53df1094082fe515c8c1e74b6d8d05f18/ruff-0.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d4176f3d194afbdaee6e41b9ccb1a2c287dba8700047df474abfbe773825d1cb", size = 10338501 }, + { url = "https://files.pythonhosted.org/packages/f2/11/cc1284d3e298c45a817a6aadb6c3e1d70b45c9b36d8d9cce3387b495a03a/ruff-0.15.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b17c886fb88203ced3afe7f14e8d5ae96e9d2f4ccc0ee66aa19f2c2675a27e4", size = 10670693 }, + { url = "https://files.pythonhosted.org/packages/ce/9e/f8288b034ab72b371513c13f9a41d9ba3effac54e24bfb467b007daee2ca/ruff-0.15.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:49fafa220220afe7758a487b048de4c8f9f767f37dfefad46b9dd06759d003eb", size = 10416177 }, + { url = "https://files.pythonhosted.org/packages/85/71/504d79abfd3d92532ba6bbe3d1c19fada03e494332a59e37c7c2dabae427/ruff-0.15.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2ab8427e74a00d93b8bda1307b1e60970d40f304af38bccb218e056c220120d", size = 11221886 }, + { url = "https://files.pythonhosted.org/packages/43/5a/947e6ab7a5ad603d65b474be15a4cbc6d29832db5d762cd142e4e3a74164/ruff-0.15.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:195072c0c8e1fc8f940652073df082e37a5d9cb43b4ab1e4d0566ab8977a13b7", size = 12075183 }, + { url = "https://files.pythonhosted.org/packages/9f/a1/0b7bb6268775fdd3a0818aee8efd8f5b4e231d24dd4d528ced2534023182/ruff-0.15.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a0996d486af3920dec930a2e7daed4847dfc12649b537a9335585ada163e9e", size = 11516575 }, + { url = "https://files.pythonhosted.org/packages/30/c3/bb5168fc4d233cc06e95f482770d0f3c87945a0cd9f614b90ea8dc2f2833/ruff-0.15.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bef2cb556d509259f1fe440bb9cd33c756222cf0a7afe90d15edf0866702431", size = 11306537 }, + { url = "https://files.pythonhosted.org/packages/e4/92/4cfae6441f3967317946f3b788136eecf093729b94d6561f963ed810c82e/ruff-0.15.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:030d921a836d7d4a12cf6e8d984a88b66094ccb0e0f17ddd55067c331191bf19", size = 11296813 }, + { url = "https://files.pythonhosted.org/packages/43/26/972784c5dde8313acde8ac71ba8ac65475b85db4a2352a76c9934361f9bc/ruff-0.15.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0e783b599b4577788dbbb66b9addcef87e9a8832f4ce0c19e34bf55543a2f890", size = 10633136 }, + { url = "https://files.pythonhosted.org/packages/5b/53/3985a4f185020c2f367f2e08a103032e12564829742a1b417980ce1514a0/ruff-0.15.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ae90592246625ba4a34349d68ec28d4400d75182b71baa196ddb9f82db025ef5", size = 10424701 }, + { url = "https://files.pythonhosted.org/packages/d3/57/bf0dfb32241b56c83bb663a826133da4bf17f682ba8c096973065f6e6a68/ruff-0.15.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1f111d62e3c983ed20e0ca2e800f8d77433a5b1161947df99a5c2a3fb60514f0", size = 10873887 }, + { url = "https://files.pythonhosted.org/packages/02/05/e48076b2a57dc33ee8c7a957296f97c744ca891a8ffb4ffb1aaa3b3f517d/ruff-0.15.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:06f483d6646f59eaffba9ae30956370d3a886625f511a3108994000480621d1c", size = 11404316 }, + { url = "https://files.pythonhosted.org/packages/88/27/0195d15fe7a897cbcba0904792c4b7c9fdd958456c3a17d2ea6093716a9a/ruff-0.15.11-py3-none-win32.whl", hash = "sha256:476a2aa56b7da0b73a3ee80b6b2f0e19cce544245479adde7baa65466664d5f3", size = 10655535 }, + { url = "https://files.pythonhosted.org/packages/3a/5e/c927b325bd4c1d3620211a4b96f47864633199feed60fa936025ab27e090/ruff-0.15.11-py3-none-win_amd64.whl", hash = "sha256:8b6756d88d7e234fb0c98c91511aae3cd519d5e3ed271cae31b20f39cb2a12a3", size = 11779692 }, + { url = "https://files.pythonhosted.org/packages/63/b6/aeadee5443e49baa2facd51131159fd6301cc4ccfc1541e4df7b021c37dd/ruff-0.15.11-py3-none-win_arm64.whl", hash = "sha256:063fed18cc1bbe0ee7393957284a6fe8b588c6a406a285af3ee3f46da2391ee4", size = 11032614 }, +] + +[[package]] +name = "scikit-rf" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pandas" }, + { name = "scipy" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/bb/36d5d359137435e1776c44aaf5861aa84727ad728ac979ec76a52e3e5b28/scikit_rf-1.11.0.tar.gz", hash = "sha256:ac6c532e327da473abb15864105337424061a9d36429808362de0247eb2906d1", size = 577744 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/53/301380bcb71e136d944363f9172491730ad3f03d0cef598d57a65db38d84/scikit_rf-1.11.0-py3-none-any.whl", hash = "sha256:a8e7c8e3b89630685b1e1ab4c48fe19a6f830bbf31c26cd6f438e90902c2b9c5", size = 627060 }, +] + +[[package]] +name = "scipy" +version = "1.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881 }, + { url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012 }, + { url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935 }, + { url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466 }, + { url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618 }, + { url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798 }, + { url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154 }, + { url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540 }, + { url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107 }, + { url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272 }, + { url = "https://files.pythonhosted.org/packages/40/41/5bf55c3f386b1643812f3a5674edf74b26184378ef0f3e7c7a09a7e2ca7f/scipy-1.16.3-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81fc5827606858cf71446a5e98715ba0e11f0dbc83d71c7409d05486592a45d6", size = 36659043 }, + { url = "https://files.pythonhosted.org/packages/1e/0f/65582071948cfc45d43e9870bf7ca5f0e0684e165d7c9ef4e50d783073eb/scipy-1.16.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:c97176013d404c7346bf57874eaac5187d969293bf40497140b0a2b2b7482e07", size = 28898986 }, + { url = "https://files.pythonhosted.org/packages/96/5e/36bf3f0ac298187d1ceadde9051177d6a4fe4d507e8f59067dc9dd39e650/scipy-1.16.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2b71d93c8a9936046866acebc915e2af2e292b883ed6e2cbe5c34beb094b82d9", size = 20889814 }, + { url = "https://files.pythonhosted.org/packages/80/35/178d9d0c35394d5d5211bbff7ac4f2986c5488b59506fef9e1de13ea28d3/scipy-1.16.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3d4a07a8e785d80289dfe66b7c27d8634a773020742ec7187b85ccc4b0e7b686", size = 23565795 }, + { url = "https://files.pythonhosted.org/packages/fa/46/d1146ff536d034d02f83c8afc3c4bab2eddb634624d6529a8512f3afc9da/scipy-1.16.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0553371015692a898e1aa858fed67a3576c34edefa6b7ebdb4e9dde49ce5c203", size = 33349476 }, + { url = "https://files.pythonhosted.org/packages/79/2e/415119c9ab3e62249e18c2b082c07aff907a273741b3f8160414b0e9193c/scipy-1.16.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:72d1717fd3b5e6ec747327ce9bda32d5463f472c9dce9f54499e81fbd50245a1", size = 35676692 }, + { url = "https://files.pythonhosted.org/packages/27/82/df26e44da78bf8d2aeaf7566082260cfa15955a5a6e96e6a29935b64132f/scipy-1.16.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fb2472e72e24d1530debe6ae078db70fb1605350c88a3d14bc401d6306dbffe", size = 36019345 }, + { url = "https://files.pythonhosted.org/packages/82/31/006cbb4b648ba379a95c87262c2855cd0d09453e500937f78b30f02fa1cd/scipy-1.16.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5192722cffe15f9329a3948c4b1db789fbb1f05c97899187dcf009b283aea70", size = 38678975 }, + { url = "https://files.pythonhosted.org/packages/c2/7f/acbd28c97e990b421af7d6d6cd416358c9c293fc958b8529e0bd5d2a2a19/scipy-1.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:56edc65510d1331dae01ef9b658d428e33ed48b4f77b1d51caf479a0253f96dc", size = 38555926 }, + { url = "https://files.pythonhosted.org/packages/ce/69/c5c7807fd007dad4f48e0a5f2153038dc96e8725d3345b9ee31b2b7bed46/scipy-1.16.3-cp312-cp312-win_arm64.whl", hash = "sha256:a8a26c78ef223d3e30920ef759e25625a0ecdd0d60e5a8818b7513c3e5384cf2", size = 25463014 }, + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856 }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306 }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371 }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877 }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103 }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297 }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756 }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566 }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877 }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366 }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931 }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081 }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244 }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753 }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912 }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371 }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477 }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678 }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178 }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246 }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469 }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043 }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952 }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512 }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639 }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729 }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251 }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681 }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423 }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027 }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379 }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052 }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183 }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174 }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852 }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595 }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269 }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779 }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128 }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "soupsieve" +version = "2.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016 }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, +] + +[[package]] +name = "tzdata" +version = "2026.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952 }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584 }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, +]